diff --git a/README.md b/README.md index e9478fc..b08bccd 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,18 @@ # OpenScan2 - 3D Scanner -## Related and more specific repositories + +Please take a look at the current [CHANGELOG](./docs/changelog.md) + +This is not the official OpenScan repository. This is a fork of [Thomas Megel](https://github.com/OpenScanEu) work but completly user-centric. Openscan is great in both software and hardware an +and Thomas has done a great job. But openscan has those things that: +* Users hate and complain continually and there is no one fixing nor acepting fixes/features +* The workflow has ups and downs and some interactions feel buggy. +The aim of this project is to tackle both weaknesses. COnvert this to a pleasant experience fro the burning of the image to the exporting of the model from the scanner. + +## Official Openscan repositories: If you want to take part in the development of a specific part of the OpenScan system, feel free to join: +* [OpenScan2 - Official Openscan files](https://github.com/OpenScanEu/OpenScan2) * [OpenScanCloud - Web API for photogrammetry processing of image files](https://github.com/OpenScanEu/OpenScanCloud) * [OpenScan-Design - 3D printable files and other design approaches](https://github.com/OpenScanEu/OpenScan-Design) * [OpenScan-PCB - A place to discuss and improve the PCB designs](https://github.com/OpenScanEu/OpenScan-PCB) @@ -10,6 +20,6 @@ If you want to take part in the development of a specific part of the OpenScan s ## Contribution and contributors -The project is based on the contribution of many great and open-minded people by doing tutorials on Youtube, comments on Reddit, publications on GitHub and many other places. Without all those voluntary contributors, this project would not be possible at all. Please feel free to join the discussions and development preferably in this repository or on [r/OpenScan](https://www.reddit.com/r/OpenScan/), [Facebook - LowBudget3DScan](https://www.facebook.com/groups/142108429832711) or [OpenScan.eu/forum](https://openscan.eu/forum) +The official project is based on the contribution of many great and open-minded people by doing tutorials on Youtube, comments on Reddit, publications on GitHub and many other places. Without all those voluntary contributors, this project would not be possible at all. Please feel free to join the discussions and development preferably in this repository or on [r/OpenScan](https://www.reddit.com/r/OpenScan/), [Facebook - LowBudget3DScan](https://www.facebook.com/groups/142108429832711) or [OpenScan.eu/forum](https://openscan.eu/forum) Thank you! diff --git a/docs/ADR/API_definition.md b/docs/ADR/API_definition.md new file mode 100644 index 0000000..858cd41 --- /dev/null +++ b/docs/ADR/API_definition.md @@ -0,0 +1,78 @@ +# ADR: Design and Implementation of OpenScan API + +## Status + +Accepted + +## Context + +The OpenScan Meanwhile project requires a robust API to facilitate communication between the front-end interface and the underlying hardware components, including the camera and motors. The API must support various operations such as taking photos, controlling the camera settings, managing system states (shutdown and reboot), and operating motors, as well as feedback to the user. + +## Decision + +We will implement a RESTful API using Flask and Flask-RESTX, structured to provide clear and organized access to system functionalities. The API will be versioned and will include the following namespaces: + +1. **System Operations (`/v1/system`)**: + - **GET `/status`**: Retrieve the current status of the system, including elapsed time and estimated time remaining for ongoing operations. + - **GET `/shutdown`**: Initiate a shutdown of the Raspberry Pi. + - **GET `/reboot`**: Initiate a reboot of the Raspberry Pi. + - **GET `/ringlight`**: Control the state of the ringlight (on/off). + +![System](../img/Openscan%20Api%20System.png) + +2. **Camera Operations (`/v1/camera`)**: + - **GET `/picam2_init`**: Initialize the camera and set up configurations. + - **GET `/picam2_take_photo`**: Capture a photo, process it, and save it to a specified location. + - **GET `/picam2_take_photo_raw`**: Capture a photo and return it in raw format. + - **GET `/picam2_focus`**: Set the focus of the camera to a specified position. + - **GET `/picam2_af`**: Trigger auto-focus functionality. + - **GET `/picam2_exposure`**: Set the camera's exposure time. + - **GET `/picam2_contrast`**: Adjust the camera's contrast settings. + - **GET `/picam2_saturation`**: Adjust the camera's saturation settings. + - **GET `/picam2_switch_mode`**: Switch between different camera modes. + - **GET `/picam2_show_mode`**: Retrieve the current camera mode. + +![Camera](../img/Openscan%20Api%20Camera.png) + +3. **Motor Operations (`/v1/motor`)**: + - **GET `/motor_run`**: Control a specified motor, allowing for angle adjustments and endstop configurations. + +![Motor](../img/Openscan%20Api%20Motor.png) +## Consequences + +### Positive + +1. **Modular Design**: The API is organized into namespaces, making it easy to understand and extend in the future. +2. **Versioning**: The API is versioned (`/v1`), allowing for backward compatibility as new features are added in future versions. +3. **Clear Documentation**: Each endpoint is documented with parameters and expected responses, facilitating easier integration and usage. + + +### Negative + +1. **Complexity**: The introduction of multiple namespaces and endpoints may increase the complexity of the codebase. +2. **Error Handling**: While basic error handling is implemented, more comprehensive error management may be required as the API evolves. +3. **Performance**: Depending on the implementation of the underlying hardware interactions, performance may vary, especially during high-load operations. + +## Implementation + +The API is implemented using Flask and Flask-RESTX, with the following key components: + +- **Flask**: A lightweight WSGI web application framework for Python. +- **Flask-RESTX**: An extension for Flask that simplifies the creation of RESTful APIs. +- **Picamera2**: A library for controlling the Raspberry Pi camera. +- **GPIO**: A library for controlling the Raspberry Pi's GPIO pins. + +### Example Endpoint + +**GET `/v1/system/shutdown`** + +- **Description**: Initiates a shutdown of the Raspberry Pi. +- **Response**: + - **200 OK**: If the shutdown is initiated successfully. + - **500 Internal Server Error**: If an error occurs while processing the request. + +## Notes + +- Consider implementing more robust logging and monitoring for the API to track usage and errors. +- Future versions of the API may include additional features such as user authentication, more granular control over camera settings, and enhanced error reporting. +- The API should be designed to be scalable and can be easily integrated with other systems and services. \ No newline at end of file diff --git a/docs/Telegram.md b/docs/Telegram.md new file mode 100644 index 0000000..ec8b080 --- /dev/null +++ b/docs/Telegram.md @@ -0,0 +1,52 @@ +# Telegram Messaging +### Why +Would it be great to be alerted when a long session ends? The aim of this feature is to have a way (in this case, via telegram) to know when a session is started (giving some basic information about what will happen) and another message when the session ends. + +### How +Its only some conditions along the existing flows. If you have activated (and properly configurated) the `Telegram Api Token` and `Telegram Client_id` you will receive the status messages to telegram. + + + +## Setup +Everything is managed by [botfather](https://telegram.me/BotFather). Follow the next steps: + +Request a new bot: send the command `/newbot`. The response to that command will be: +``` +Alright, a new bot. How are we going to call it? Please choose a name for your bot. +``` +Now you name your bot whtever you like. This is how you will identify your bot in your telegram user list from now on. +After choosing the name you willget that response: + +``` +Done! Congratulations on your new bot. You will find it at t.me/openscan_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this. + +Use this token to access the HTTP API: +4815162342:N334AA-covfefeskibidi +Keep your token secure and store it safely, it can be used by anyone to control your bot. + +For a description of the Bot API, see this page: https://core.telegram.org/bots/api +``` + +This is a really important part: store that token safely as its the way you will securely talk with your bot. + +Now you have 2 ways to fint your "client_id": + +The first is open a chat with [@userinfo](https://t.me/userinfobot). If you type ```/start```there you will get an ```Id```response and you can complete the process. + +Another way is opening an url in your browser to get your id: + +``` +https://api.telegram.org/bot/getUpdates +``` + +you will revive a response like this: + +``` +{"ok":true,"result":[{"update_id":462349, +"message":{"message_id":123,"from":{"id":1111111,"is_bot":false,"first_name":"Meanwhile","username":"meanwhile","language_code":"ca"}, +``` + +The Client_id is the "id" field (not the "update_id" or "message_id"). +Upon completing the settings with that information you are ready to go! + + \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..c9ff705 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,52 @@ +# Changelog + +### 2024-11S +* fixed: shutdown and reboot button in the UI +* Added Swagger UI to help build, design and document the API +* Fixed the FKMSGate +* New update mechanism: Releases have their own version with their own stable, beta and meanwhile flavours. + +### 2024-02-26 +* Fixed: Without telegram configured it was impossible to finish a scan (hanged on finish). But who in their sanity would not use telegram if available right? +* After a reboot/shutdown, if you forgot to close that tab it will not trigger a disaster when you are scanning in the future + +### 2024-02-23 Meanwhile (23F) + +This is the beginning of a fork. After several attempts to add a feature and get silence as response I have decided to create my own OpenScan fork. +* added: When doing a focus stack session you can store the contents inside the zip with all the photos sorted in their own folder. Some focus stacking applications will benefit from this. +* added: [You can now get alerts on Telegram](Telegram.md) when the session starts and the session ends +* fixed: The "delete all files" operation no longer prevents the refresh of the file list + +### 2022-05-19 documentation +* changed: overall structure --> the OpenScan2 repository will serve as a central hub for all informations concerning OpenScan (i.e. firmware, hardware, tutorials ...) +### 2022-05-11 beta +* added: changelog and version (finally ;) +* added: create an update using the node-red-backend inject node ("create beta" and "prepare image creation" in "update" tab) +* fixed: Error handling in flask (when no preview is taken) +* fixed: Error when upload failed + node red restarted (multiple instances of curl) +* fixed: When closing the browser session/missing the popup after the routine, the data set got lost (if this happens, just restart the device and it will be moved to the right location) +### 2022-04-26 beta +* added: donation button ;) +* fixed: the wonderful camera position algorithm was faulty and a bit inefficient +* fixed: downscaling the preview image caused the preview to disappear (when crop value was to high) +* fixed: delay_before and delay_after are now properly applied, so that you can set a delay before/after taking a photo +* fixed: updates might crash the selected camera --> it is now necessary to re-select the camera after certain updates +### 2022-04-21 beta +* added: timer (ETA) until a routine is done +* added: showing progress, while files are being split (before uploading to OpenScanCloud) +* added: infotexts (FINALLY :) +* added: several stats/device information +* fixed: combining two sets did not delete the smaller set +### 2022-04-20 beta & main +* !fixed: pi cameras (v1.3, v2.1 and HQ) finally work and can be simply selected in the settings menu +* !fixed: Raspberry Pi 3B+ and 4 work! (the main limiting factor now is the RAM, where at least 1GB RAM is needed) +* fixed: live preview sometimes did not work. This has been a network speed issue and has been solved by downscaling the image (resolution can be set) +* fixed: it is now possible to delete individual sets. +* fixed: it is now possible to use all LEDs. +* added: Turntable mode (disable the second axis) +* added: Pause scan. You can pause and un-pause the scan by simply pressing the button +* added: second scan pass. When one scan is done, you can immediately run a second pass. This is especially useful, if you want to re-orient the object +* added: auto-timeout. Turn off the ringlight (todo: and motors) after 300 seconds (value can be set) +* added: diskspace warning. When free diskspace drops below a given threshold (4GB by default), a warning message will appear +* changed: new background image, minor design changes +* changed: log file can be easily generated and downloaded by clicking a button (update&info tab) \ No newline at end of file diff --git a/docs/img/Openscan Api Camera.png b/docs/img/Openscan Api Camera.png new file mode 100644 index 0000000..6fb9af2 Binary files /dev/null and b/docs/img/Openscan Api Camera.png differ diff --git a/docs/img/Openscan Api Motor.png b/docs/img/Openscan Api Motor.png new file mode 100644 index 0000000..b8cbc15 Binary files /dev/null and b/docs/img/Openscan Api Motor.png differ diff --git a/docs/img/Openscan Api System.png b/docs/img/Openscan Api System.png new file mode 100644 index 0000000..c290c1c Binary files /dev/null and b/docs/img/Openscan Api System.png differ diff --git a/docs/img/telegram_bot_watch.jpg b/docs/img/telegram_bot_watch.jpg new file mode 100644 index 0000000..e0728d8 Binary files /dev/null and b/docs/img/telegram_bot_watch.jpg differ diff --git a/docs/img/telegram_configuration.png b/docs/img/telegram_configuration.png new file mode 100644 index 0000000..d16de23 Binary files /dev/null and b/docs/img/telegram_configuration.png differ diff --git a/update/betaArdu/OpenScan.py b/update/2024-11S/beta/OpenScan.py similarity index 97% rename from update/betaArdu/OpenScan.py rename to update/2024-11S/beta/OpenScan.py index e0edd35..e634511 100644 --- a/update/betaArdu/OpenScan.py +++ b/update/2024-11S/beta/OpenScan.py @@ -78,10 +78,8 @@ def add_wifi_network(ssid, password, country): with open(conf_file, "w") as f: f.write(updated_content) os.system("sudo systemctl restart wpa_supplicant@wlan0") - return True - def load_str(name): filename = basepath+'settings/'+name if not isfile(filename): @@ -165,7 +163,14 @@ def motorrun(motor,angle,ES_enable=False,ES_start_state = True): step_count=-step_count for x in range(step_count): if ES_enable == True and GPIO.input(ES_pin) != ES_start_state: - break + i = 0 + while i <= 10: + if GPIO.input(ES_pin) == ES_start_state: + i = 11 + if i == 10: + return + i = i + 1 + GPIO.output(steppin, GPIO.HIGH) if x<=ramp and x<=step_count/2: delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) @@ -194,8 +199,6 @@ def take_photo(file): model=load_str('model') - - shutter = str(load_int('cam_shutter')) saturation = load_str('cam_saturation') contrast = load_str('cam_contrast') diff --git a/update/2024-11S/beta/OpenScanStatistics.py b/update/2024-11S/beta/OpenScanStatistics.py new file mode 100755 index 0000000..68005af --- /dev/null +++ b/update/2024-11S/beta/OpenScanStatistics.py @@ -0,0 +1,18 @@ +import csv + +class ScanStatistics: + def __init__(self, filename="/home/pi/OpenScan/statistics/statistics.csv"): + self.filename = filename + self.header = ["arch", "shield", "date_init", "date_end", "num_photos", "done-photos", "camera", "aborted"] + + def write_statistics(self, arch, shield, date_init, date_end, num_photos, done_photos, camera, aborted): + data = [arch, shield, date_init, date_end, num_photos, done_photos, camera, aborted] + + with open(self.filename, "a", newline='') as csv_file: + csv_writer = csv.writer(csv_file, delimiter=';') + + # Write header if file is empty + if csv_file.tell() == 0: + csv_writer.writerow(self.header) + + csv_writer.writerow(data) diff --git a/update/2024-11S/beta/config.txt b/update/2024-11S/beta/config.txt new file mode 100755 index 0000000..3bb8fef --- /dev/null +++ b/update/2024-11S/beta/config.txt @@ -0,0 +1,34 @@ +# For more options and information see +# http://rpf.io/configtxt +# Some settings may impact device functionality. See link above for details + +# Additional overlays and parameters are documented /boot/overlays/README + +# Automatically load overlays for detected cameras +camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[pi4] +# Run as fast as firmware / board allows +arm_boost=1 +dtoverlay=imx519,cma-512 + +[all] +camera_auto_detect=0 +gpu_mem=256 +dtoverlay=imx519 \ No newline at end of file diff --git a/update/2024-11S/beta/expand_root.sh b/update/2024-11S/beta/expand_root.sh new file mode 100755 index 0000000..f4f7148 --- /dev/null +++ b/update/2024-11S/beta/expand_root.sh @@ -0,0 +1,7 @@ +#!/bin/bash +if test -f "/boot/expand_root"; then + echo "expanding root partition" + raspi-config --expand-rootfs + rm -fr /boot/expand_root + shutdown -r now +fi diff --git a/update/2024-11S/beta/fla.py b/update/2024-11S/beta/fla.py new file mode 100644 index 0000000..026867e --- /dev/null +++ b/update/2024-11S/beta/fla.py @@ -0,0 +1,519 @@ +from flask import Flask, request, redirect, send_file, send_from_directory +from flask_restx import Resource, Api, Namespace +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont +from time import sleep, time +from OpenScan import load_int, load_float, load_bool, ringlight, motorrun +import RPi.GPIO as GPIO +from math import sqrt +import os +import math +from skimage import feature, color, transform +import numpy as np +from scipy import ndimage +import socket + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +app = Flask(__name__) +api = Api(app, version='1.0', title='OpenScan API', description='API for OpenScan') + +v1 = Namespace('v1', description='API v1') +# Create a namespace for system operations +system_ns = Namespace('system', description='System operations') +camera_ns = Namespace('camera', description='Camera operations') +motor_ns = Namespace('motor', description='Motor operations') + +api.add_namespace(v1, path='/v1') +api.add_namespace(system_ns, path='/v1/system') +api.add_namespace(camera_ns, path='/v1/camera') +api.add_namespace(motor_ns, path='/v1/motor') + +basedir = '/home/pi/OpenScan/' +timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + + +################################################################################################################### + + +@system_ns.route('/status') +class Status(Resource): + def get(self): + ''' + Get system status + ''' + import os + import json + from time import time + + if os.path.exists('/tmp/status.json'): + try: + with open('/tmp/status.json', 'r') as status_file: + status = json.load(status_file) + + elapsed_time = time() - status['start_time'] + estimated_total_time = (elapsed_time / status['current_photo']) * status['total_photos'] + time_remaining = max(0, estimated_total_time - elapsed_time) + + status.update({ + "status": "running", + "elapsed_time": int(elapsed_time), + "estimated_total_time": int(estimated_total_time), + "time_remaining": int(time_remaining) + }) + + return status, 200 + except Exception as e: + return {"error": f"Error reading status file: {str(e)}"}, 500 + else: + return {"status": "idle"}, 200 + +@system_ns.route('/shutdown') +class Shutdown(Resource): + @system_ns.doc(params={'token': 'Shutdown token for authentication'}) + def get(self): + '''Shutdown the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('shutdown -h now') + return {'message': 'Shutting down'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/reboot') +class Reboot(Resource): + @system_ns.doc(params={'token': 'Reboot token for authentication'}) + def get(self): + '''Reboot the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('reboot -h') + return {'message': 'Rebooting'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/ringlight') +class Ringlight(Resource): + @system_ns.doc(params={'state': 'Ringlight state (0 or 1)'}) + def get(self): + '''Set ringlight state''' + state = int(request.args.get('state')) + if state == 0: + ringlight(1, False) + ringlight(2, False) + else: + ringlight(1, True) + ringlight(2, True) + return {'message': f'Ringlight set to {state}'}, 200 + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) + + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') + + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wait 3-5s + return {'message': 'Auto focus triggered'}, 200 + +@motor_ns.route('/motor_run') +class MotorRun(Resource): + ''' + Run a motor + ''' + @motor_ns.doc(params={ + 'motor': 'Motor name (rotor, tt, extra)', + 'angle': 'Angle to rotate (integer)', + 'ES_enable': 'Enable endstop (optional, boolean)', + 'ES_start_state': 'Endstop start state (optional, boolean)' + }) + @motor_ns.response(400, 'Bad Request') + def get(self): + '''Run a motor''' + motor = request.args.get('motor') + if not motor: + return {'error': 'Motor parameter is required'}, 400 + if motor not in ['rotor', 'tt', 'extra']: + return {'error': 'Invalid motor name'}, 400 + + try: + angle = int(request.args.get('angle')) + except (TypeError, ValueError): + return {'error': 'Angle must be an integer'}, 400 + + ES_enable = request.args.get('ES_enable', 'false').lower() == 'true' + ES_start_state = request.args.get('ES_start_state', 'true').lower() == 'true' + + try: + motorrun(motor, angle, ES_enable, ES_start_state) + except Exception as e: + return {'error': f'Error running motor: {str(e)}'}, 500 + + return {'message': f'Motor {motor} run to {angle} degrees'}, 200 + + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + + +if __name__ == '__main__': +# app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) + app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) + diff --git a/update/2024-11S/beta/flows.json b/update/2024-11S/beta/flows.json new file mode 100644 index 0000000..6fa42e1 --- /dev/null +++ b/update/2024-11S/beta/flows.json @@ -0,0 +1,9594 @@ +[ + { + "id": "e6f4d02efb300ea9", + "type": "tab", + "label": "Init", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "481edaf6db5a7a54", + "type": "tab", + "label": "Scan", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "80a3942785a26c29", + "type": "tab", + "label": "Files", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "e43a27722b508115", + "type": "tab", + "label": "Settings", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "a5557543ccff5889", + "type": "tab", + "label": "Update", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "87715429b0b1c9a3", + "type": "tab", + "label": "Statistics", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", + "type": "ui_tab", + "name": "Scan", + "icon": "dashboard", + "order": 2, + "disabled": false, + "hidden": false + }, + { + "id": "5c06cb6bcc371ee6", + "type": "ui_base", + "theme": { + "name": "theme-dark", + "lightTheme": { + "default": "#0094CE", + "baseColor": "#0094CE", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "darkTheme": { + "default": "#097479", + "baseColor": "#097479", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "customTheme": { + "name": "Untitled Theme 1", + "default": "#4B7930", + "baseColor": "#4B7930", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false + }, + "themeState": { + "base-color": { + "default": "#097479", + "value": "#097479", + "edited": false + }, + "page-titlebar-backgroundColor": { + "value": "#097479", + "edited": false + }, + "page-backgroundColor": { + "value": "#111111", + "edited": false + }, + "page-sidebar-backgroundColor": { + "value": "#333333", + "edited": false + }, + "group-textColor": { + "value": "#0eb8c0", + "edited": false + }, + "group-borderColor": { + "value": "#555555", + "edited": false + }, + "group-backgroundColor": { + "value": "#333333", + "edited": false + }, + "widget-textColor": { + "value": "#eeeeee", + "edited": false + }, + "widget-backgroundColor": { + "value": "#097479", + "edited": false + }, + "widget-borderColor": { + "value": "#333333", + "edited": false + }, + "base-font": { + "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + } + }, + "angularTheme": { + "primary": "indigo", + "accents": "blue", + "warn": "red", + "background": "grey", + "palette": "light" + } + }, + "site": { + "name": "OpenScan", + "hideToolbar": "false", + "allowSwipe": "false", + "lockMenu": "false", + "allowTempTheme": "true", + "dateFormat": "DD/MM/YYYY", + "sizes": { + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, + "cx": 6, + "cy": 6, + "px": 0, + "py": 0 + } + } + }, + { + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 6 + }, + { + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 5 + }, + { + "id": "b5fdd57b.15eda8", + "type": "ui_group", + "name": "Main", + "tab": "15a222ed.d70a7d", + "order": 1, + "disp": false, + "width": 13, + "collapse": false + }, + { + "id": "db43d646.2074c8", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", + "order": 2, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "15a222ed.d70a7d", + "type": "ui_tab", + "name": "Files&Cloud", + "icon": "dashboard", + "order": 3, + "disabled": false, + "hidden": false + }, + { + "id": "365a30d0dfa83e95", + "type": "ui_group", + "name": "settings", + "tab": "e23b837a9f040895", + "order": 1, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "ac7409105cfecac6", + "type": "ui_group", + "name": "advanced", + "tab": "e23b837a9f040895", + "order": 3, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "729f9ea6e3513c9b", + "type": "ui_group", + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "5b3e5aca21140e9a", + "type": "ui_group", + "name": "Update", + "tab": "b3150b13e34b1fe8", + "order": 1, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "b3150b13e34b1fe8", + "type": "ui_tab", + "name": "OpenScan", + "icon": "dashboard", + "order": 1, + "disabled": false, + "hidden": true + }, + { + "id": "ddbd496e.93a288", + "type": "ui_group", + "name": "Manage Updates", + "tab": "d25e08b4.5b27e8", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "3ce32450.e0cffc", + "type": "ui_group", + "name": "System & Stats", + "tab": "d25e08b4.5b27e8", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "d25e08b4.5b27e8", + "type": "ui_tab", + "name": "Update & Info", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "4390b2ebcbbe104c", + "type": "ui_group", + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "8ab79a98e536e0d6", + "type": "ui_group", + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Motor", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 1, + "width": 1, + "height": 1 + }, + { + "id": "33b6d7317d1524b8", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "aaf5b874c52a58aa", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, + "height": 1 + }, + { + "id": "f8d8740dcbf499fb", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 11, + "width": 1, + "height": 1 + }, + { + "id": "7ac0cb556740d159", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, + "height": 1 + }, + { + "id": "4de2414e29020c74", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "90223f7ddc082321", + "order": 2, + "width": 7, + "height": 1 + }, + { + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 + }, + { + "id": "ce21673092264c38", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, + "height": 1 + }, + { + "id": "3f7b77f8a1675d27", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "12b719cba49817c9", + "order": 7, + "width": 4, + "height": 1 + }, + { + "id": "0799b02d12fc3a14", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "7a3279eea439bcdd", + "order": 25, + "width": 6, + "height": 1 + }, + { + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "ac59b8fb186de073", + "type": "ui_group", + "name": "[Statistics]", + "tab": "656b4eb8b15dab8f", + "order": 3, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "656b4eb8b15dab8f", + "type": "ui_tab", + "name": "Statistics", + "icon": "dashboard", + "disabled": false, + "hidden": false + }, + { + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 460, + "wires": [ + [ + "949bafced17d66d6" + ] + ] + }, + { + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 460, + "wires": [ + [] + ] + }, + { + "id": "a1f0ed7d5a9d670e", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.1", + "topic": "", + "x": 110, + "y": 60, + "wires": [ + [ + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6" + ] + ] + }, + { + "id": "544d20f02215011a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 60, + "wires": [ + [ + "c77552216a8bb781" + ] + ] + }, + { + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 540, + "y": 60, + "wires": [ + [ + "960912e90ba5b5bc" + ] + ] + }, + { + "id": "960912e90ba5b5bc", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244", + "9b3e6a06c82a0f52" + ], + "x": 645, + "y": 60, + "wires": [] + }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "168d72a54504b327", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "5/0.1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "5", + "topic": "", + "payload": "", + "payloadType": "str", + "x": 100, + "y": 380, + "wires": [ + [ + "6c6ef2255a7d39e5" + ] + ] + }, + { + "id": "6c6ef2255a7d39e5", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "repeat 5s/0.1s", + "mode": "link", + "links": [ + "61990987acd0f263", + "2415272f42ce468c", + "6bf8344af427a6ba" + ], + "x": 205, + "y": 380, + "wires": [] + }, + { + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", + "outputs": 1, + "x": 270, + "y": 140, + "wires": [ + [ + "eb1a2387a1eeea76" + ] + ] + }, + { + "id": "b1e2491c952f84c9", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, + "wires": [ + [ + "200d4b9951b6e066" + ] + ] + }, + { + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf", + "65518f3d4e3095e5" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 800, + "y": 40, + "wires": [ + [ + "544d20f02215011a" + ] + ] + }, + { + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 580, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", + "outputs": 1, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 540, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 620, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 580, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 660, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "8955d11554f55e63", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "5b3e5aca21140e9a", + "order": 1, + "width": 6, + "height": 3, + "passthru": false, + "label": "Install Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "date", + "topic": "", + "topicType": "str", + "x": 120, + "y": 820, + "wires": [ + [ + "1e7457ea9c2c5e09" + ] + ] + }, + { + "id": "1e7457ea9c2c5e09", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "update", + "mode": "link", + "links": [ + "39a502b38837273d" + ], + "x": 245, + "y": 820, + "wires": [] + }, + { + "id": "245e4341d4fb611c", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 790, + "y": 540, + "wires": [ + [ + "627406f3611511dc" + ] + ] + }, + { + "id": "627406f3611511dc", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "write", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 930, + "y": 540, + "wires": [ + [ + "50eeb3e362f9027f" + ] + ] + }, + { + "id": "88b1bddde110298a", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 650, + "y": 540, + "wires": [ + [ + "245e4341d4fb611c" + ] + ] + }, + { + "id": "50eeb3e362f9027f", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244", + "9b3e6a06c82a0f52" + ], + "x": 1015, + "y": 540, + "wires": [] + }, + { + "id": "4f3121f158f06a61", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", + "outputs": 1, + "x": 860, + "y": 580, + "wires": [ + [] + ] + }, + { + "id": "4a8a04b1e5dca8fe", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "run rotor till endstop", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 690, + "y": 580, + "wires": [ + [ + "4f3121f158f06a61" + ] + ] + }, + { + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 580, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "e548168473aa85d6", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 5, + "width": 0, + "height": 0, + "passthru": false, + "label": "Statistics", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "5", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 100, + "y": 700, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "6a3d9acbe097a3d2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 120, + "wires": [ + [ + "cb6ebdabaaf7d0da" + ] + ] + }, + { + "id": "7ef6f1b5c67201fe", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "86f7d1b2d763f6e2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 160, + "wires": [ + [ + "c8a3fde5206ce1ae" + ] + ] + }, + { + "id": "fd799c931139764d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 240, + "wires": [ + [ + "87be854db758a9a6" + ] + ] + }, + { + "id": "d5140d455122c49a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 280, + "wires": [ + [ + "9daea4bd57f7a00e" + ] + ] + }, + { + "id": "194f3590dd4f6e3d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "2de69452e829d780", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", + "label": "", + "tooltip": "", + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, + "height": 1, + "passthru": true, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 320, + "y": 80, + "wires": [ + [ + "734ac3bff2df6837" + ] + ] + }, + { + "id": "97170908e1f4ac55", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 80, + "wires": [ + [ + "58e565fea35cb667" + ] + ] + }, + { + "id": "734ac3bff2df6837", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 55, + "y": 80, + "wires": [ + [ + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" + ] + ] + }, + { + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/v1/camera/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", + "outputs": 1, + "x": 510, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "c7f5808d753480d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 170, + "y": 200, + "wires": [ + [ + "11f41a6030578ef4" + ] + ] + }, + { + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 200, + "wires": [ + [ + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "855cbcadef1163c5", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 840, + "wires": [ + [ + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" + ] + ] + }, + { + "id": "1a443e20a973d2f1", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw true", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 630, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "d1b87196ae5373ed", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw false", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 430, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "03d92601c62b79d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "4s/0.5", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "Repeat", + "payload": "0.1", + "payloadType": "str", + "x": 100, + "y": 840, + "wires": [ + [ + "855cbcadef1163c5" + ] + ] + }, + { + "id": "41e6a4649b6afbfb", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Take Preview Shot", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/v1/camera/picam2_take_photo')\n\nreturn msg\n", + "outputs": 1, + "x": 450, + "y": 800, + "wires": [ + [ + "1a443e20a973d2f1", + "296636b7467fc745" + ] + ] + }, + { + "id": "85a268108250ba88", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", + "order": 1, + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 450, + "y": 840, + "wires": [ + [ + "417f653ca0dfdcfc", + "180476141c2a44ad" + ] + ] + }, + { + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, + "wires": [] + }, + { + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, + "wires": [ + [ + "e864254b18c23dd1" + ] + ] + }, + { + "id": "e864254b18c23dd1", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int\n\nif 'payload' not in msg:\n return\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'))\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'))\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'))\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'))\n\n", + "outputs": 1, + "x": 780, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "180476141c2a44ad", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 880, + "wires": [ + [ + "8cbdbfecbd12ef83" + ] + ] + }, + { + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", + "outputs": 1, + "x": 870, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", + "outputs": 1, + "x": 440, + "y": 720, + "wires": [ + [ + "923be3b2b25224b4" + ] + ] + }, + { + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "c8a3fde5206ce1ae", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 160, + "wires": [ + [ + "034ec9f59e50a361", + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "034ec9f59e50a361", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, + "wires": [ + [ + "194f3590dd4f6e3d" + ] + ] + }, + { + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, + "wires": [ + [ + "2de69452e829d780" + ] + ] + }, + { + "id": "cb6ebdabaaf7d0da", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 120, + "wires": [ + [ + "7ef6f1b5c67201fe" + ] + ] + }, + { + "id": "82ecd3cd971cb7ea", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, + "height": 1, + "name": "projectname", + "label": "Projectname", + "format": "", + "layout": "row-left", + "className": "", + "x": 530, + "y": 40, + "wires": [] + }, + { + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, + "wires": [ + [ + "06e1e19835a9816e" + ] + ] + }, + { + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, + "wires": [ + [ + "1fe18f3b0b52aabd" + ] + ] + }, + { + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "7dd287f40385922f", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "start ", + "group": "365a30d0dfa83e95", + "order": 10, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-play", + "payload": "", + "payloadType": "date", + "topic": "enabled", + "topicType": "str", + "x": 130, + "y": 1040, + "wires": [ + [ + "33d94a04b96a2de0", + "6d15f717d5a11002", + "9a6b30a0175a8ecd" + ] + ] + }, + { + "id": "579f2211199fd6ab", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "stop", + "group": "365a30d0dfa83e95", + "order": 12, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-stop", + "payload": "numberofphotos", + "payloadType": "global", + "topic": "", + "topicType": "str", + "x": 490, + "y": 1100, + "wires": [ + [ + "1787f08ed7070ddd", + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "1787f08ed7070ddd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "stop", + "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "outputs": 1, + "x": 630, + "y": 1100, + "wires": [ + [] + ] + }, + { + "id": "e9b13dfd9f8d3711", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 395, + "y": 1000, + "wires": [] + }, + { + "id": "9654deebb668e012", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "1s", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 290, + "y": 1140, + "wires": [ + [ + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "8367cfa0bf5bc5df", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine", + "links": [ + "200d4b9951b6e066", + "8689e938.dd9e38", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 45, + "y": 1040, + "wires": [ + [ + "7dd287f40385922f" + ] + ] + }, + { + "id": "fb13752beddee9f2", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 535, + "y": 1060, + "wires": [] + }, + { + "id": "33d94a04b96a2de0", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1100, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "c1c044f3c2139f68", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 1140, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "1daf9e3a5bd5ab48", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 430, + "y": 1040, + "wires": [ + [ + "fb13752beddee9f2" + ] + ] + }, + { + "id": "6d15f717d5a11002", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 1000, + "wires": [ + [ + "e9b13dfd9f8d3711" + ] + ] + }, + { + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "# The contents of this file are embedded in the OpenScan app (Node-RED)\nfrom OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom OpenScanStatistics import ScanStatistics\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\nfrom datetime import datetime\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname, remove\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\nimport json\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\nstats = ScanStatistics()\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/v1/camera/picam2_switch_mode?mode=1')\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\narchitecture = load_str(\"architecture\")\ncamera_model = load_str(\"camera\")\nshield = \"green\"\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\ndelete_aborted = load_bool('delete_aborted')\nif load_bool('rotor_enable_endstop'):\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True, False)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_current_timestamp():\n return datetime.now().strftime(\"%Y-%m-%d %H:%M\")\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/v1/camera/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/v1/camera/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n\n motorrun('tt',tt_angle)\n motorrun('rotor',rotor_angle)\n return\n \ncounter2 = 0\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/v1/camera/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\ndate_init = get_current_timestamp()\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\n\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n \n # Calculate time remaining and write status to /tmp/status as JSON\n elapsed_time = time() - starttime\n estimated_total_time = (elapsed_time / counter) * photocount * steps\n time_remaining = max(0, estimated_total_time - elapsed_time)\n \n status = {\n \"scan_name\": projectname,\n \"total_photos\": photocount,\n \"current_photo\": counter,\n \"stacksize\": steps,\n \"start_time\": int(starttime),\n }\n with open('/tmp/status.json', 'w') as status_file:\n json.dump(status, status_file)\n\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/v1/camera/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\n# Delete the status.json file\n\ntry:\n remove('/tmp/status.json')\nexcept FileNotFoundError:\n pass # File doesn't exist, so no need to delete\nexcept Exception as e:\n print(f\"Error deleting /tmp/status.json: {e}\")\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\ndate_end = get_current_timestamp()\n\nif counter == photocount:\n stats.write_statistics(architecture, shield, date_init, date_end, photocount, counter, camera_model, False)\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\nelse:\n stats.write_statistics(architecture, shield, date_init, date_end, photocount, counter, camera_model, True)\n if delete_aborted:\n remove(zippath)\n else:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, + "wires": [ + [ + "1daf9e3a5bd5ab48", + "795c85ad4f109567" + ] + ] + }, + { + "id": "afe47a9eaae6f67f", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, + "height": 1, + "name": "", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", + "className": "", + "x": 340, + "y": 40, + "wires": [] + }, + { + "id": "8608517d0567d63f", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 40, + "wires": [ + [ + "afe47a9eaae6f67f" + ] + ] + }, + { + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 55, + "y": 40, + "wires": [ + [ + "8608517d0567d63f" + ] + ] + }, + { + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, + "wires": [ + [ + "9774e7ad3b506354" + ] + ] + }, + { + "id": "9774e7ad3b506354", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 380, + "wires": [ + [ + "f0af909f3e739b22" + ] + ] + }, + { + "id": "39c744466a21735e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 40, + "wires": [ + [ + "fa181d22775c2ce6" + ] + ] + }, + { + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 80, + "wires": [ + [ + "c615034ea6b26174" + ] + ] + }, + { + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 480, + "wires": [ + [ + "237c2135cdad86ea" + ] + ] + }, + { + "id": "dd7fb8791d34c751", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 880, + "wires": [ + [ + "180476141c2a44ad" + ] + ] + }, + { + "id": "5baf89a2682265f7", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "enable led", + "links": [ + "eb1a2387a1eeea76" + ], + "x": 145, + "y": 880, + "wires": [ + [ + "dd7fb8791d34c751" + ] + ] + }, + { + "id": "6a26e8a7253d708c", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 40, + "wires": [ + [ + "39c744466a21735e" + ] + ] + }, + { + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, + "wires": [ + [ + "61aab497fa50898e" + ] + ] + }, + { + "id": "9fd259de91de1da1", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 735, + "y": 40, + "wires": [ + [ + "6a26e8a7253d708c", + "35ad7e55833836c1" + ] + ] + }, + { + "id": "fa181d22775c2ce6", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 40, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "c615034ea6b26174", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 80, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "ae5ee8787145906d", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import camera\ncamera('/v1/camera/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", + "outputs": 1, + "x": 1290, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "f0af909f3e739b22", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Features", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 420, + "wires": [ + [ + "710fc2dbb5ef0167" + ] + ] + }, + { + "id": "710fc2dbb5ef0167", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "d93c2b67bcf23b9a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 480, + "wires": [ + [ + "5e83b653850fa16e" + ] + ] + }, + { + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 95, + "y": 480, + "wires": [ + [ + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" + ] + ] + }, + { + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "c8b93b42c720b9cf", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", + "links": [ + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" + ], + "x": 85, + "y": 380, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 620, + "y": 1000, + "wires": [] + }, + { + "id": "ea54fcc2.cfcc2", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "get dirs", + "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "outputs": 1, + "x": 480, + "y": 180, + "wires": [ + [ + "f3662f8c7d3d7a2d", + "01e4783e148c6698" + ] + ] + }, + { + "id": "2f4c0f98.dee2", + "type": "link in", + "z": "80a3942785a26c29", + "name": "filelist", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "a4f09e25.02569", + "ed35109311335099", + "fb13752beddee9f2" + ], + "x": 355, + "y": 220, + "wires": [ + [ + "ea54fcc2.cfcc2" + ] + ] + }, + { + "id": "952ce286.4ffd4", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 4, + "width": 6, + "height": 1, + "name": "Status", + "label": "Status", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 250, + "y": 60, + "wires": [] + }, + { + "id": "d4383424.7807c8", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "upload", + "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", + "outputs": 2, + "x": 530, + "y": 460, + "wires": [ + [ + "9a132ab1.b21658" + ], + [ + "3d16b3789632784d", + "9a132ab1.b21658" + ] + ] + }, + { + "id": "50710948.71c308", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "set", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 750, + "y": 180, + "wires": [ + [ + "ada1b6f7cccc9344", + "85839a17fb7b58b9" + ] + ] + }, + { + "id": "834046a4.647938", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 5, + "width": 6, + "height": 1, + "name": "Set", + "label": "Set:", + "format": "{{msg.payload.Name}}", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 220, + "wires": [] + }, + { + "id": "9a132ab1.b21658", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.true", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 780, + "y": 460, + "wires": [ + [ + "8689e938.dd9e38" + ] + ] + }, + { + "id": "3c67e97b.9d19a6", + "type": "function", + "z": "80a3942785a26c29", + "name": "enable", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 130, + "y": 340, + "wires": [ + [ + "7a93d1e18254685c", + "e434ef42bd6b92e8", + "d5d840183025d91b", + "ab9e90ab5a53a0dd", + "478994f671a3907d" + ] + ] + }, + { + "id": "bfc01f26.c32cf", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.false", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 500, + "wires": [ + [ + "f20f2dbc.0f123" + ] + ] + }, + { + "id": "b33d604c.5f1a6", + "type": "link in", + "z": "80a3942785a26c29", + "name": "enable cloud", + "links": [ + "4082b136.dae18", + "8689e938.dd9e38", + "bd75f33b8a57c522", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 35, + "y": 340, + "wires": [ + [ + "3c67e97b.9d19a6" + ] + ] + }, + { + "id": "f6bd1a04.470838", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "set", + "tot": "global" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 410, + "y": 460, + "wires": [ + [ + "d4383424.7807c8" + ] + ] + }, + { + "id": "4082b136.dae18", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "b33d604c.5f1a6", + "87574a42938afec4" + ], + "x": 715, + "y": 140, + "wires": [] + }, + { + "id": "f20f2dbc.0f123", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 515, + "y": 500, + "wires": [] + }, + { + "id": "8689e938.dd9e38", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 875, + "y": 460, + "wires": [] + }, + { + "id": "15de0ebb.616d61", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 380, + "wires": [ + [ + "a7d89487.ee8858" + ] + ] + }, + { + "id": "a7d89487.ee8858", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", + "outputs": 1, + "x": 690, + "y": 380, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "a4f09e25.02569", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2" + ], + "x": 775, + "y": 360, + "wires": [] + }, + { + "id": "7a93d1e18254685c", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "92c98e6ce7cd25f9" + ], + "x": 235, + "y": 500, + "wires": [] + }, + { + "id": "4d99c601c9881680", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "refresh", + "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", + "outputs": 2, + "x": 320, + "y": 180, + "wires": [ + [ + "ea54fcc2.cfcc2", + "b42e061fb1f1f3d7" + ], + [ + "6434e713f088012b" + ] + ] + }, + { + "id": "372e95797a3f2f3b", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "limit :)", + "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", + "outputs": 1, + "x": 90, + "y": 220, + "wires": [ + [ + "573edbfdb7500ddc" + ] + ] + }, + { + "id": "573edbfdb7500ddc", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 230, + "y": 220, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "dacb1f078b624e10", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 340, + "wires": [ + [ + "c8d65cc7c2ff7c36" + ] + ] + }, + { + "id": "92c98e6ce7cd25f9", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "7a93d1e18254685c", + "bd75f33b8a57c522" + ], + "x": 35, + "y": 180, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "3d16b3789632784d", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 770, + "y": 500, + "wires": [ + [] + ] + }, + { + "id": "6434e713f088012b", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 470, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "c8d65cc7c2ff7c36", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", + "outputs": 1, + "x": 690, + "y": 340, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "f4e9a4bd79b4221f", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 340, + "wires": [ + [ + "dacb1f078b624e10" + ] + ] + }, + { + "id": "2806bf08ea21216d", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 380, + "wires": [ + [ + "15de0ebb.616d61" + ] + ] + }, + { + "id": "61990987acd0f263", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 45, + "y": 60, + "wires": [ + [ + "51579603bce21e98" + ] + ] + }, + { + "id": "e8e488a6dd5d0b33", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "Download", + "order": 8, + "width": 3, + "height": 1, + "format": "\n
Download\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 880, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "0c387c0291d6c131", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 750, + "y": 260, + "wires": [ + [ + "e8e488a6dd5d0b33" + ] + ] + }, + { + "id": "e5f38b4a07a5e278", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 655, + "y": 220, + "wires": [ + [ + "834046a4.647938" + ] + ] + }, + { + "id": "e434ef42bd6b92e8", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "upload2", + "order": 7, + "width": 3, + "height": 1, + "format": "upload", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 460, + "wires": [ + [ + "f6bd1a04.470838" + ] + ] + }, + { + "id": "c46e10b9c201913e", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "refresh", + "order": 2, + "width": 4, + "height": 1, + "format": "refresh{{msg.text}}", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 160, + "y": 180, + "wires": [ + [ + "372e95797a3f2f3b", + "4d99c601c9881680" + ] + ] + }, + { + "id": "d5d840183025d91b", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del set", + "order": 11, + "width": 2, + "height": 1, + "format": "delete set", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 380, + "wires": [ + [ + "2806bf08ea21216d" + ] + ] + }, + { + "id": "ab9e90ab5a53a0dd", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del ", + "order": 10, + "width": 2, + "height": 1, + "format": "delete all", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 340, + "wires": [ + [ + "f4e9a4bd79b4221f" + ] + ] + }, + { + "id": "478994f671a3907d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "combine", + "order": 9, + "width": 2, + "height": 1, + "format": "combine", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 540, + "wires": [ + [ + "51bfd0fb7b1d292e" + ] + ] + }, + { + "id": "189c1eed09624a7b", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 580, + "wires": [ + [ + "1493398979a63775" + ] + ] + }, + { + "id": "51bfd0fb7b1d292e", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 420, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "da325be8e74179be", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", + "outputs": 1, + "x": 560, + "y": 580, + "wires": [ + [ + "ed35109311335099" + ] + ] + }, + { + "id": "ed35109311335099", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "2f4c0f98.dee2" + ], + "x": 655, + "y": 580, + "wires": [] + }, + { + "id": "1493398979a63775", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Combine", + "x": 420, + "y": 580, + "wires": [ + [ + "da325be8e74179be" + ] + ] + }, + { + "id": "ada1b6f7cccc9344", + "type": "link out", + "z": "80a3942785a26c29", + "name": "combine", + "mode": "link", + "links": [ + "6dd356510c446cf4" + ], + "x": 835, + "y": 180, + "wires": [] + }, + { + "id": "6dd356510c446cf4", + "type": "link in", + "z": "80a3942785a26c29", + "name": "combine", + "links": [ + "ada1b6f7cccc9344" + ], + "x": 175, + "y": 580, + "wires": [ + [ + "189c1eed09624a7b" + ] + ] + }, + { + "id": "b42e061fb1f1f3d7", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "397ab7f44b893c89", + "3876d5cbd248592b" + ], + "x": 435, + "y": 140, + "wires": [] + }, + { + "id": "b99505440832439f", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "diskspace", + "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", + "outputs": 1, + "x": 800, + "y": 100, + "wires": [ + [ + "92047434f8e9f927" + ] + ] + }, + { + "id": "92047434f8e9f927", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 950, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "f3662f8c7d3d7a2d", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "minute", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 650, + "y": 100, + "wires": [ + [ + "b99505440832439f" + ] + ] + }, + { + "id": "51579603bce21e98", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "read", + "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", + "outputs": 1, + "x": 130, + "y": 60, + "wires": [ + [ + "952ce286.4ffd4" + ] + ] + }, + { + "id": "9a5baae623355f9d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "preview", + "order": 6, + "width": 6, + "height": 6, + "format": "
\n\n\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1020, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "85839a17fb7b58b9", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "preview", + "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", + "outputs": 1, + "x": 880, + "y": 220, + "wires": [ + [ + "9a5baae623355f9d" + ] + ] + }, + { + "id": "01e4783e148c6698", + "type": "ui_table", + "z": "80a3942785a26c29", + "group": "b5fdd57b.15eda8", + "name": "", + "order": 1, + "width": 13, + "height": 7, + "columns": [ + { + "field": "Date", + "title": "Date", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Name", + "title": "Name", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Photos", + "title": "Photos", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Duration", + "title": "ΔT", + "width": "60", + "align": "left", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Size", + "title": "Size", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Status", + "title": "Status", + "width": "140", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + } + ], + "outputs": 1, + "cts": true, + "x": 610, + "y": 180, + "wires": [ + [ + "4082b136.dae18", + "50710948.71c308", + "834046a4.647938", + "0c387c0291d6c131" + ] + ] + }, + { + "id": "cb3437ec113e1b6f", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "SSH", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 3, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 390, + "y": 360, + "wires": [ + [ + "c24f61b87e3226dd" + ] + ] + }, + { + "id": "60fd0adce1cfeb82", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Samba", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "test2", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 400, + "wires": [ + [ + "441d3ef525e901da" + ] + ] + }, + { + "id": "c24f61b87e3226dd", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "ssh", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", + "outputs": 1, + "x": 530, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "c013e836e759a085", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "4390b2ebcbbe104c", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "label": "Terms Of Use", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 120, + "y": 320, + "wires": [ + [ + "b78346ca3ce70c68" + ] + ] + }, + { + "id": "f0d8dbcca76a1926", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "Agree", + "cancel": "Disagree", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 410, + "y": 320, + "wires": [ + [ + "e95b86cbac1b03b9" + ] + ] + }, + { + "id": "34374044c0030625", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "General", + "group": "4390b2ebcbbe104c", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

General Settings

Terms Of Use

In order to use the OpenScanCloud, please read the terms of use as files will be transmitted from your device to the OpenScan Servers.

SSH

SSH can be used to access the Raspberry Pi and modify core files of the operating system. Please deactivate, if you do not want to use this feature.

If you want to use it, the default user is pi, password: raspberry. Please change the password immediately. 

Samba

Samba s a network local file sharing server, which allows accessing the Raspberry Pi's file system through the explorer (and other programs like FileZilla). You can use it to transfer custom photo sets to the device in order to use the OpenScanCloud. Therefore, you need to transfer the zip file containing your photos to the following folder /OpenScan/scans/

You can access the Raspberry Pis file system by inserting the following line into your Windows explorer: 

\\\\OpenScan/PiShare/OpenScan/scans/

username: pi, password: raspberry

Please deactivate the local file sharing if you do not intend to use it

Advanced Settings

Enable a ton of additional settings, which should be changed only if you know what you are doing ;)

Model

Device model you are using: OpenScan Mini or OpenScan Classic. Setting the device affects the settings of the motor (gear ratio, acceleration, speed). You can change those values manually in the advanced settings.

Camera

A wide range of camera modules is supported (Pi camera v1.3, v2.1, HQ, Arducam IMX519, IMX290, IMX378, OV9281). If you encounter any issues with those models, please check the orientation of the camera ribbon cable and its connectors.

DSLR (gphoto) - connect a wide range of DSLR cameras to the device through USB. See GPhoto for a full list of supported devices.

External camera - triggering any camera through an isolated GPIO signal on the front side of the pi shield.

Shutdown/Reboot

Always use the shutdown button before you power off your Raspberry Pi.

Restore Default Settings

In case you want to restore the default settings

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "b2b6bf23c9989133", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Pinout", + "group": "70d0be671bf03ca7", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Pinout

ONLY CHANGE THE PINOUT IF YOU ARE ABSOLUTELY SURE! CHANGES CAN DAMAGE THE RASPBERRY PI AND ANY PERIPHERALS!


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "441d3ef525e901da", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "smb", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", + "outputs": 1, + "x": 530, + "y": 400, + "wires": [ + [] + ] + }, + { + "id": "3256bab150113a48", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Motor", + "group": "7a3279eea439bcdd", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Motor Settings

Turntable Mode

Activate turntable mode in order to deactivate the rotor. The routine will only move the turntable and take a given number of photos.

Rotor - Start Angle, Min and Max Angle

Since this version of OpenScan does not have an endstop (yet), it is necessary to tell the device its position when the routine is being started. 0° corresponds to the horizontal (natural) orientation.

After that, the device will equally space the image positions between angle min and angle max.

Rotor/Turntable

Steps per rotation -  defines the number of steps it takes to move the axis 360°. It is defined by A*B*C, where A is the number of steps for one revolution of the given stepper motor (normally 200), B is the microstepping used (normally 16), and C the gear ratio (1 for the turntable and 15 or 5,33 for the OpenScan Mini and Classic respectively)

Delay - time in microseconds between each step of the motor. Lower this value if the movement is too fast

Acceleration - a factor defining how fast the delay time between each step is being changed during acceleration and deceleration phases. Lower this value in order to make the movement smoother.

Acceleration ramp - the number of steps allowed for the acceleration processes. Increase this value, if you want smoother movement.

Manual Angle - Defines the degree value for the manual movement through the arrow buttons in the scan menu

Direction - If needed, reverse the movement (in case the arrow buttons and movement do not correspond). Alternatively, you can flip the motor cable 180° (BUT MAKE SURE TO POWER OFF THE DEVICE!)


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 140, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "7a186669a17daa71", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "camera", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Camera Settings

Jpeg quality

Value in percent, which usually does not need to be changed.

Downscale Preview

The preview image has to be scaled down depending on your network speed. If you want to have a higher quality preview image, you can increase this value, which defines the maximal width/height value. If the value is too high, the preview window might not update

Image Rotation

Change the image rotation, if needed.

Timeout

Defines the time in seconds, when the libcamera command (used for the camera modules) will timeout. Increase this value, if the camera does not get triggered in each position.

Delay Before/After

A fixed delay in seconds before and/or after a photo is taken. Increase this value when the photos have visual motion blur.

AWBG, Gain, Contrast, Saturation

Under most circumstances, you do not need to touch these values.

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 420, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "edac7dd292e7e486", + "type": "comment", + "z": "e43a27722b508115", + "name": "General Settings", + "info": "", + "x": 120, + "y": 280, + "wires": [] + }, + { + "id": "161b52034e578ee2", + "type": "comment", + "z": "e43a27722b508115", + "name": "Network", + "info": "", + "x": 100, + "y": 720, + "wires": [] + }, + { + "id": "f6d6cc35679ede63", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "more sets", + "label": "Advanced Settings", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 480, + "wires": [ + [ + "f06a7bcad524e9f9" + ] + ] + }, + { + "id": "29745a36fc157f3f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "more sets", + "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", + "outputs": 2, + "x": 820, + "y": 480, + "wires": [ + [ + "8750ad979e9ea246" + ], + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "bf23328f9fb11b22", + "type": "ui_ui_control", + "z": "e43a27722b508115", + "name": "change visibility", + "events": "all", + "x": 600, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "b37be1d222bc70c9", + "type": "inject", + "z": "e43a27722b508115", + "name": "1s_repeater", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "1", + "crontab": "", + "once": true, + "onceDelay": "2", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 150, + "y": 60, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "89eedf29b404f750", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, + "wires": [ + [ + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" + ] + ] + }, + { + "id": "2050de5d9e02f69f", + "type": "comment", + "z": "e43a27722b508115", + "name": "Info Texts", + "info": "", + "x": 100, + "y": 140, + "wires": [] + }, + { + "id": "ded3086945a6d4b5", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "check ip address", + "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", + "outputs": 1, + "x": 250, + "y": 940, + "wires": [ + [ + "3cfe464506f46ecd" + ] + ] + }, + { + "id": "3cfe464506f46ecd", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Your local IP:", + "format": "{{msg.ip}}", + "layout": "row-spread", + "className": "", + "x": 430, + "y": 940, + "wires": [] + }, + { + "id": "bd206ad109831e6a", + "type": "comment", + "z": "e43a27722b508115", + "name": "OpenScanCloud", + "info": "", + "x": 120, + "y": 1260, + "wires": [] + }, + { + "id": "b70a9a665c1e4d36", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Cloud-settings", + "group": "12b719cba49817c9", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

OpenScanCloud

OpenScanCloud is a free/donation-based cloud processing service, which will convert your photos into 3d models using latest photogrammetry technology. Feel free to support the project with a small donation at BuyMeACoffee.

The only requirement to use this service is a one-time, free-of-charge registration (which is solely an anti-spam measure). By filling out the registration form, you will receive an individual access token.

Register

In order to use the OpenScanCloud, you will have to enter your name and email. It might take 1-3 days to create the access token, which will be sent to your mail address. Please check your spam folder.

Enter Token

Please enter your individual token here in order to activate the cloud functionality. The token will be verified immediately. In case of any problems, please contact cloud@openscan.eu

Token

A shorted version of your token will be displayed here. Please include a copy of this shorted token in any support requests cloud@openscan.eu

Credit (GB)

Each token comes with a given amount of 'credit' which is another measure against spam. The given number in Gigabyte indicates the amount of data, that you can process on the servers. 

IMPORTANT: The credit can be increased at any time by sending a (nice) mail to cloud@openscan.eu

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 260, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "c9f0566601a3e130", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Number of Photos:", + "format": "{{msg.limit_photos}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 1400, + "wires": [] + }, + { + "id": "9bd86d27ea499a2a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Filesize (GB):", + "format": "{{msg.limit_filesize}}", + "layout": "row-spread", + "className": "", + "x": 390, + "y": 1440, + "wires": [] + }, + { + "id": "2c37f7030810d234", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Credit (GB):", + "format": "{{msg.credit}}", + "layout": "row-spread", + "className": "", + "x": 370, + "y": 1480, + "wires": [] + }, + { + "id": "f40286c18afd4501", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "save", + "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", + "outputs": 2, + "x": 750, + "y": 1340, + "wires": [ + [ + "455a5266017ea121", + "50f73cee213ec05c" + ], + [ + "264eece408043021" + ] + ] + }, + { + "id": "455a5266017ea121", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 890, + "y": 1300, + "wires": [ + [] + ] + }, + { + "id": "c368df68593bc2bf", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Token", + "tooltip": "", + "group": "12b719cba49817c9", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 350, + "y": 1360, + "wires": [ + [ + "18fd1afa768187b3" + ] + ] + }, + { + "id": "18fd1afa768187b3", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "Save?", + "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", + "outputs": 2, + "x": 470, + "y": 1360, + "wires": [ + [ + "418aea2ec65573a0" + ], + [ + "9792c89c5f4429f9" + ] + ] + }, + { + "id": "f90a98899b7a71d0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "text", + "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", + "outputs": 1, + "x": 230, + "y": 1360, + "wires": [ + [ + "c368df68593bc2bf" + ] + ] + }, + { + "id": "b4c843620c251c43", + "type": "link in", + "z": "e43a27722b508115", + "name": "token", + "links": [ + "960912e90ba5b5bc", + "50f73cee213ec05c", + "9792c89c5f4429f9", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1360, + "wires": [ + [ + "f90a98899b7a71d0" + ] + ] + }, + { + "id": "418aea2ec65573a0", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 1340, + "wires": [ + [ + "f40286c18afd4501" + ] + ] + }, + { + "id": "9792c89c5f4429f9", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "b4c843620c251c43" + ], + "x": 555, + "y": 1380, + "wires": [] + }, + { + "id": "264eece408043021", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "5d267acc10020091", + "3876d5cbd248592b" + ], + "x": 835, + "y": 1380, + "wires": [] + }, + { + "id": "3876d5cbd248592b", + "type": "link in", + "z": "e43a27722b508115", + "name": "OSCparameters", + "links": [ + "960912e90ba5b5bc", + "264eece408043021", + "b42e061fb1f1f3d7", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1400, + "wires": [ + [ + "5daca3ec47f8e7fc" + ] + ] + }, + { + "id": "50f73cee213ec05c", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "b4c843620c251c43", + "5d267acc10020091" + ], + "x": 835, + "y": 1340, + "wires": [] + }, + { + "id": "95578e54a9b61cba", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 250, + "y": 1540, + "wires": [ + [ + "d7a5693da7855da8" + ] + ] + }, + { + "id": "d7a5693da7855da8", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", + "outputs": 2, + "x": 390, + "y": 1540, + "wires": [ + [ + "2b02b97dd1614e52" + ], + [ + "183a629accb417b1" + ] + ] + }, + { + "id": "183a629accb417b1", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1580, + "wires": [ + [] + ] + }, + { + "id": "2b02b97dd1614e52", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1540, + "wires": [ + [ + "3e4c15d7b538f816" + ] + ] + }, + { + "id": "3bf622f344172721", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "SUBMIT", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 810, + "y": 1540, + "wires": [ + [ + "e431cb2b8d217cee" + ] + ] + }, + { + "id": "e431cb2b8d217cee", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", + "outputs": 1, + "x": 950, + "y": 1540, + "wires": [ + [ + "106874534890f229" + ] + ] + }, + { + "id": "a38d7fde5c73210f", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Register", + "group": "12b719cba49817c9", + "order": 6, + "width": 2, + "height": 1, + "passthru": false, + "label": "Register", + "tooltip": "testtesttest", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "Please enter your email address:", + "payloadType": "str", + "topic": "Requesting an OpenScanCloud Token", + "topicType": "str", + "x": 100, + "y": 1540, + "wires": [ + [ + "95578e54a9b61cba" + ] + ] + }, + { + "id": "106874534890f229", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 1090, + "y": 1540, + "wires": [ + [] + ] + }, + { + "id": "5daca3ec47f8e7fc", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", + "outputs": 1, + "x": 230, + "y": 1400, + "wires": [ + [ + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" + ] + ] + }, + { + "id": "f34de19d4cf810a9", + "type": "comment", + "z": "e43a27722b508115", + "name": "Motor", + "info": "", + "x": 90, + "y": 1740, + "wires": [] + }, + { + "id": "26c2b58e21f97475", + "type": "comment", + "z": "e43a27722b508115", + "name": "Camera", + "info": "", + "x": 90, + "y": 2500, + "wires": [] + }, + { + "id": "a8ec972bad47a9a8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Pinout", + "info": "", + "x": 90, + "y": 2960, + "wires": [] + }, + { + "id": "b03e8b51187e88eb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "Rotor_delay (ms)", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 16, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 450, + "y": 2100, + "wires": [ + [ + "11fd3363416433f9" + ] + ] + }, + { + "id": "6aae9d4fddf08cc0", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt delay", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 30, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 420, + "y": 2340, + "wires": [ + [ + "e50492d1e18f43c6" + ] + ] + }, + { + "id": "543e1690693acbeb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 18, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 420, + "y": 2140, + "wires": [ + [ + "e8b24efb0f30288e" + ] + ] + }, + { + "id": "9a56c087d941f1da", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 20, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "100", + "max": "5000", + "step": "100", + "className": "", + "x": 440, + "y": 2180, + "wires": [ + [ + "29f576be9e292232" + ] + ] + }, + { + "id": "dfdebe10dbf0e198", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotor_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 14, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 460, + "y": 2060, + "wires": [ + [ + "78e256083f59f66f" + ] + ] + }, + { + "id": "af8dfe78cbd0c301", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, + "width": 3, + "height": 1, + "name": "rotor Accramp", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2140, + "wires": [] + }, + { + "id": "ee4b8908a5b83880", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, + "width": 3, + "height": 1, + "name": "rotor_Steps per Rotation", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 810, + "y": 2180, + "wires": [] + }, + { + "id": "c4deaa38c1b0adbf", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, + "width": 3, + "height": 1, + "name": "rotor Acc", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2100, + "wires": [] + }, + { + "id": "baec873a95fff48a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, + "width": 3, + "height": 1, + "name": "rotor_delay", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 770, + "y": 2060, + "wires": [] + }, + { + "id": "355e89ab4e5484e4", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 26, + "width": 6, + "height": 1, + "name": "tt", + "label": "TURNTABLE", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 2300, + "wires": [] + }, + { + "id": "10687d331a732790", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 32, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 410, + "y": 2380, + "wires": [ + [ + "af88b9da72917d62" + ] + ] + }, + { + "id": "721b9680a3fa460e", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 34, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "500", + "step": "1", + "className": "", + "x": 430, + "y": 2420, + "wires": [ + [ + "b1b4678827d3a6dd" + ] + ] + }, + { + "id": "c6642c7470d3820c", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "tt_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 28, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 450, + "y": 2300, + "wires": [ + [ + "eef89545ec0f6aa8" + ] + ] + }, + { + "id": "18e5918748660109", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 33, + "width": 3, + "height": 1, + "name": "ttAccramp", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2420, + "wires": [] + }, + { + "id": "8e805244dc1899e8", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 27, + "width": 3, + "height": 1, + "name": "tt_steps per Rotation", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 800, + "y": 2300, + "wires": [] + }, + { + "id": "a09e5fbea861bfb1", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 31, + "width": 3, + "height": 1, + "name": "tt Acc", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 750, + "y": 2380, + "wires": [] + }, + { + "id": "7b06448b3b222011", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 29, + "width": 3, + "height": 1, + "name": "tt_delay", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2340, + "wires": [] + }, + { + "id": "0dfc86d90258f9bb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 22, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 430, + "y": 2220, + "wires": [ + [ + "c4b5a38c5c1df3d2" + ] + ] + }, + { + "id": "9319d7d4f34c6d22", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, + "width": 3, + "height": 1, + "name": "rotor_angle", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 770, + "y": 2220, + "wires": [] + }, + { + "id": "1610895f430b9aca", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 36, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 420, + "y": 2460, + "wires": [ + [ + "0f3367983bb8e159" + ] + ] + }, + { + "id": "96a9febc0928b6f0", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 35, + "width": 3, + "height": 1, + "name": "tt_angle", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2460, + "wires": [] + }, + { + "id": "e2c5ea8c16a5ea32", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, + "width": 6, + "height": 1, + "name": "rotor", + "label": "ROTOR", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 1820, + "wires": [] + }, + { + "id": "277037c4716d85bf", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 38, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 410, + "y": 2500, + "wires": [ + [ + "c9d2e31514def4fc" + ] + ] + }, + { + "id": "1361134e9847f003", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 24, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 420, + "y": 2260, + "wires": [ + [ + "523717b0f218a5fd" + ] + ] + }, + { + "id": "6b0d58943ecb8bb2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 37, + "width": 3, + "height": 1, + "name": "tt_dir", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2500, + "wires": [] + }, + { + "id": "08f93dd2aeedb391", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, + "width": 3, + "height": 1, + "name": "rotor_dir", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2260, + "wires": [] + }, + { + "id": "46b91bef44714366", + "type": "link in", + "z": "e43a27722b508115", + "name": "advanced settings", + "links": [ + "8750ad979e9ea246" + ], + "x": 95, + "y": 100, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "8750ad979e9ea246", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "46b91bef44714366" + ], + "x": 955, + "y": 480, + "wires": [] + }, + { + "id": "2522f888dc58972f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_before", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 430, + "y": 2600, + "wires": [ + [ + "5c752757090c49d2" + ] + ] + }, + { + "id": "30e8df3d616512d8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_gain", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "10", + "step": "0.1", + "className": "", + "x": 400, + "y": 2640, + "wires": [ + [ + "a1769f0277834f6d" + ] + ] + }, + { + "id": "d855d926df89d65b", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_contrast", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2760, + "wires": [ + [ + "1a8b0ba21b4f3005", + "654bc70a18820828" + ] + ] + }, + { + "id": "7617517dc8ba2859", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_saturation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2800, + "wires": [ + [ + "dc8fc962ff7d594b", + "e64feb03a791ca33" + ] + ] + }, + { + "id": "cbaa23c34e10fae1", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_jpeg_q", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 3, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "100", + "step": "1", + "className": "", + "x": 410, + "y": 2840, + "wires": [ + [ + "00e7836ccb3c4d0c" + ] + ] + }, + { + "id": "bbe443b039a14e21", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, + "width": 3, + "height": 1, + "name": "delay_before", + "label": "Delay before", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2600, + "wires": [] + }, + { + "id": "d320ed3d701e6cc2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, + "width": 3, + "height": 1, + "name": "gain", + "label": "Gain", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2640, + "wires": [] + }, + { + "id": "f5834dd4646c8af9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, + "width": 3, + "height": 1, + "name": "contrast", + "label": "Contrast", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2760, + "wires": [] + }, + { + "id": "ae9a4e19469813ef", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, + "width": 3, + "height": 1, + "name": "saturation", + "label": "Saturation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2800, + "wires": [] + }, + { + "id": "bd629d0d31233c8b", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 2, + "width": 3, + "height": 1, + "name": "jpegQ", + "label": "Jpeg Quality", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2840, + "wires": [] + }, + { + "id": "e89f61dbe6a6cffe", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ext", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 3, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3000, + "wires": [ + [ + "885bc559fafec5f2" + ] + ] + }, + { + "id": "ece38cb172a12d75", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 2, + "width": 4, + "height": 1, + "name": "ext", + "label": "External Camera", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3000, + "wires": [] + }, + { + "id": "70014da0b6ab6698", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3040, + "wires": [ + [ + "f70321c96bf81360" + ] + ] + }, + { + "id": "29634ea5f6d666df", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 4, + "width": 4, + "height": 1, + "name": "light1", + "label": "Light 1", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3040, + "wires": [] + }, + { + "id": "2544963852c6881a", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 7, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3080, + "wires": [ + [ + "95e1603bbd06a69d" + ] + ] + }, + { + "id": "27903533cd85a59e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 6, + "width": 4, + "height": 1, + "name": "light2", + "label": "Light 2", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3080, + "wires": [] + }, + { + "id": "a1394401246eb735", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotordir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 9, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3120, + "wires": [ + [ + "a8f92ea6bf394640" + ] + ] + }, + { + "id": "bc0aa4bacdfa94ea", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 8, + "width": 4, + "height": 1, + "name": "rotordir", + "label": "Rotor direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3120, + "wires": [] + }, + { + "id": "f15ca4518b5f223e", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotorstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 11, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3160, + "wires": [ + [ + "06397bb46b3bb541" + ] + ] + }, + { + "id": "0d2924b160e7e383", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 10, + "width": 4, + "height": 1, + "name": "rotorstep", + "label": "Rotor step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3160, + "wires": [] + }, + { + "id": "49900bb9047dd965", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotoren", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 13, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3200, + "wires": [ + [ + "687dcdc1ede11700" + ] + ] + }, + { + "id": "a4d743ca73ee1622", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 12, + "width": 4, + "height": 1, + "name": "rotoren", + "label": "Rotor enable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3200, + "wires": [] + }, + { + "id": "5a90224dc998b417", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttdir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 15, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3240, + "wires": [ + [ + "e220740c0d38ccb0" + ] + ] + }, + { + "id": "67dc1b544c4ddf9f", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 14, + "width": 4, + "height": 1, + "name": "ttdir", + "label": "Turntable direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3240, + "wires": [] + }, + { + "id": "d2364ab09627fe94", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 17, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3280, + "wires": [ + [ + "79d7e5a705ab813a" + ] + ] + }, + { + "id": "145b67ac40721ba6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 16, + "width": 4, + "height": 1, + "name": "ttstep", + "label": "Turntable step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3280, + "wires": [] + }, + { + "id": "eef25405472acfee", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 19, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3320, + "wires": [ + [ + "12d20f2274bcc511" + ] + ] + }, + { + "id": "35eb252a41413531", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 18, + "width": 4, + "height": 1, + "name": "endstop1", + "label": "Endstop Rotor", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3320, + "wires": [] + }, + { + "id": "74e455136b5ca5dd", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 21, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3360, + "wires": [ + [ + "a4a89668ce4c9f05" + ] + ] + }, + { + "id": "3a74f653800eb831", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 20, + "width": 4, + "height": 1, + "name": "endstop2", + "label": "Endstop Turntable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3360, + "wires": [] + }, + { + "id": "5fcef1cb2e9e4788", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "confirm", + "x": 680, + "y": 480, + "wires": [ + [ + "29745a36fc157f3f" + ] + ] + }, + { + "id": "f06a7bcad524e9f9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", + "outputs": 1, + "x": 530, + "y": 480, + "wires": [ + [ + "5fcef1cb2e9e4788" + ] + ] + }, + { + "id": "f455fb39039617ae", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_rotation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "270", + "step": "90", + "className": "", + "x": 410, + "y": 2880, + "wires": [ + [ + "3019576de193d9d6" + ] + ] + }, + { + "id": "fdfbc900fe424eb9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, + "width": 3, + "height": 1, + "name": "cam_rot", + "label": "Image Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2880, + "wires": [] + }, + { + "id": "c3699d6b9664ccca", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2060, + "wires": [ + [ + "dfdebe10dbf0e198" + ] + ] + }, + { + "id": "78e256083f59f66f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2060, + "wires": [ + [] + ] + }, + { + "id": "0f9141b401322374", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2180, + "wires": [ + [ + "9a56c087d941f1da" + ] + ] + }, + { + "id": "29f576be9e292232", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2180, + "wires": [ + [] + ] + }, + { + "id": "23e3099b34c4e475", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2220, + "wires": [ + [ + "0dfc86d90258f9bb" + ] + ] + }, + { + "id": "c4b5a38c5c1df3d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2220, + "wires": [ + [] + ] + }, + { + "id": "79a14162ac805fac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2260, + "wires": [ + [ + "1361134e9847f003" + ] + ] + }, + { + "id": "523717b0f218a5fd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2260, + "wires": [ + [] + ] + }, + { + "id": "f5cf780f3fa8997e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2100, + "wires": [ + [ + "b03e8b51187e88eb" + ] + ] + }, + { + "id": "11fd3363416433f9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2100, + "wires": [ + [] + ] + }, + { + "id": "02060b3f3b294563", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2140, + "wires": [ + [ + "543e1690693acbeb" + ] + ] + }, + { + "id": "e8b24efb0f30288e", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2140, + "wires": [ + [] + ] + }, + { + "id": "de1ad8b27b72a5ac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nsteps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", + "outputs": 1, + "noerr": 4, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2300, + "wires": [ + [ + "c6642c7470d3820c" + ] + ] + }, + { + "id": "ed4d587cb4feb064", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2420, + "wires": [ + [ + "721b9680a3fa460e" + ] + ] + }, + { + "id": "5b02160c33605ae7", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2460, + "wires": [ + [ + "1610895f430b9aca" + ] + ] + }, + { + "id": "304c135ec09801e3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2500, + "wires": [ + [ + "277037c4716d85bf" + ] + ] + }, + { + "id": "a91dcbe0f9a2416a", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2340, + "wires": [ + [ + "6aae9d4fddf08cc0" + ] + ] + }, + { + "id": "6b2eb1cb95e573f9", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2380, + "wires": [ + [ + "10687d331a732790" + ] + ] + }, + { + "id": "eef89545ec0f6aa8", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2300, + "wires": [ + [] + ] + }, + { + "id": "b1b4678827d3a6dd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2420, + "wires": [ + [] + ] + }, + { + "id": "0f3367983bb8e159", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2460, + "wires": [ + [] + ] + }, + { + "id": "c9d2e31514def4fc", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2500, + "wires": [ + [] + ] + }, + { + "id": "e50492d1e18f43c6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2340, + "wires": [ + [] + ] + }, + { + "id": "af88b9da72917d62", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2380, + "wires": [ + [] + ] + }, + { + "id": "43fe948b3e7234e2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2600, + "wires": [ + [ + "2522f888dc58972f" + ] + ] + }, + { + "id": "5c752757090c49d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2600, + "wires": [ + [] + ] + }, + { + "id": "435681b3f7625a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2640, + "wires": [ + [ + "30e8df3d616512d8" + ] + ] + }, + { + "id": "a1769f0277834f6d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2640, + "wires": [ + [] + ] + }, + { + "id": "1de07c7d285cbaf3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2760, + "wires": [ + [ + "d855d926df89d65b" + ] + ] + }, + { + "id": "1a8b0ba21b4f3005", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2760, + "wires": [ + [] + ] + }, + { + "id": "ebc9e283468eda31", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2800, + "wires": [ + [ + "7617517dc8ba2859" + ] + ] + }, + { + "id": "dc8fc962ff7d594b", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2800, + "wires": [ + [] + ] + }, + { + "id": "60d641613527c736", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2840, + "wires": [ + [ + "cbaa23c34e10fae1" + ] + ] + }, + { + "id": "00e7836ccb3c4d0c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2840, + "wires": [ + [] + ] + }, + { + "id": "7f24c0c34a88ba04", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2880, + "wires": [ + [ + "f455fb39039617ae" + ] + ] + }, + { + "id": "3019576de193d9d6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2880, + "wires": [ + [] + ] + }, + { + "id": "77bb7dc529d63a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3000, + "wires": [ + [ + "e89f61dbe6a6cffe" + ] + ] + }, + { + "id": "885bc559fafec5f2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3000, + "wires": [ + [] + ] + }, + { + "id": "cc6dabe017a9c8a8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3320, + "wires": [ + [ + "eef25405472acfee" + ] + ] + }, + { + "id": "12d20f2274bcc511", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3320, + "wires": [ + [] + ] + }, + { + "id": "dcb9fed8122759fd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3040, + "wires": [ + [ + "70014da0b6ab6698" + ] + ] + }, + { + "id": "f70321c96bf81360", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3040, + "wires": [ + [] + ] + }, + { + "id": "013d2057c2347a62", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3080, + "wires": [ + [ + "2544963852c6881a" + ] + ] + }, + { + "id": "95e1603bbd06a69d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3080, + "wires": [ + [] + ] + }, + { + "id": "f88bbf11d5aa9a14", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3120, + "wires": [ + [ + "a1394401246eb735" + ] + ] + }, + { + "id": "a8f92ea6bf394640", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3120, + "wires": [ + [] + ] + }, + { + "id": "301af70731e096e5", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3160, + "wires": [ + [ + "f15ca4518b5f223e" + ] + ] + }, + { + "id": "06397bb46b3bb541", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3160, + "wires": [ + [] + ] + }, + { + "id": "0456a9ec4c236c9e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3200, + "wires": [ + [ + "49900bb9047dd965" + ] + ] + }, + { + "id": "687dcdc1ede11700", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3200, + "wires": [ + [] + ] + }, + { + "id": "09d37ba08ec0f163", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3240, + "wires": [ + [ + "5a90224dc998b417" + ] + ] + }, + { + "id": "37d954a4cf7e87ea", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3280, + "wires": [ + [ + "d2364ab09627fe94" + ] + ] + }, + { + "id": "e220740c0d38ccb0", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3240, + "wires": [ + [] + ] + }, + { + "id": "79d7e5a705ab813a", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3280, + "wires": [ + [] + ] + }, + { + "id": "21dc963d967d9c99", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3360, + "wires": [ + [ + "74e455136b5ca5dd" + ] + ] + }, + { + "id": "a4a89668ce4c9f05", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3360, + "wires": [ + [] + ] + }, + { + "id": "22ef66b0e2058be2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 360, + "wires": [ + [ + "cb3437ec113e1b6f" + ] + ] + }, + { + "id": "9ce01c8ba97932c1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 400, + "wires": [ + [ + "60fd0adce1cfeb82" + ] + ] + }, + { + "id": "81356177176eebcf", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 7, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 480, + "wires": [ + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "b78346ca3ce70c68", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 320, + "wires": [ + [ + "f0d8dbcca76a1926" + ] + ] + }, + { + "id": "e95b86cbac1b03b9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "3e4c15d7b538f816", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 670, + "y": 1540, + "wires": [ + [ + "3bf622f344172721" + ] + ] + }, + { + "id": "0f0871baf322b6d0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1820, + "wires": [ + [ + "6ebd15c61a5ca891" + ] + ] + }, + { + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1820, + "wires": [ + [] + ] + }, + { + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, + "wires": [ + [ + "acd10a4c99ee8063" + ] + ] + }, + { + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, + "wires": [ + [ + "031d7697768d0e77" + ] + ] + }, + { + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, + "wires": [ + [ + "be1954dd71d2c94c" + ] + ] + }, + { + "id": "edb1c8fae8b65c82", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1860, + "wires": [ + [ + "3ad0f0f206e4a873" + ] + ] + }, + { + "id": "031d7697768d0e77", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1860, + "wires": [ + [] + ] + }, + { + "id": "462a8f3ca75fc3c8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1900, + "wires": [ + [ + "3b6d759ed5be647f" + ] + ] + }, + { + "id": "be1954dd71d2c94c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1900, + "wires": [ + [] + ] + }, + { + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, + "wires": [ + [ + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88", + "53681e53353db898" + ] + ] + }, + { + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, + "y": 940, + "wires": [ + [ + "ded3086945a6d4b5", + "6ea3cdab41f20f92" + ] + ] + }, + { + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, + "wires": [ + [ + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd" + ] + ] + }, + { + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2540, + "wires": [ + [ + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" + ] + ] + }, + { + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3000, + "wires": [ + [ + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8", + "21dc963d967d9c99" + ] + ] + }, + { + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 620, + "wires": [ + [ + "53e6681d7254d484" + ] + ] + }, + { + "id": "53e6681d7254d484", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 270, + "y": 620, + "wires": [ + [ + "c11e79cfa7bc10b7" + ] + ] + }, + { + "id": "c11e79cfa7bc10b7", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 620, + "wires": [ + [ + "307782d10c1acdaf" + ] + ] + }, + { + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 620, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "cca3300a8f0daf4d", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 750, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "654bc70a18820828", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_contrast?contrast=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2720, + "wires": [ + [] + ] + }, + { + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_saturation?saturation=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2680, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2560, + "wires": [ + [ + "e612073aded01a8f" + ] + ] + }, + { + "id": "0d92559980944ae3", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, + "width": 3, + "height": 1, + "name": "delay_after", + "label": "Delay after", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2560, + "wires": [] + }, + { + "id": "6281b2e6e081104d", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2560, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2560, + "wires": [ + [] + ] + }, + { + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 560, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 560, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 210, + "y": 980, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 220, + "y": 1020, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 240, + "y": 1060, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] + }, + { + "id": "a7d233f984009e2e", + "type": "function", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 440, + "y": 980, + "wires": [ + [ + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" + ] + ] + }, + { + "id": "65518f3d4e3095e5", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 1", + "links": [ + "200d4b9951b6e066" + ], + "x": 85, + "y": 980, + "wires": [ + [ + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" + ] + ] + }, + { + "id": "9b851aa999e86fd7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", + "outputs": 1, + "x": 670, + "y": 980, + "wires": [ + [ + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" + ] + ] + }, + { + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 870, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, + "wires": [] + }, + { + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", + "links": [ + "592ec13d8f8923a9" + ], + "x": 815, + "y": 1020, + "wires": [] + }, + { + "id": "1eef47e0074545a9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, + "wires": [ + [ + "c994c779e4bad800", + "36890eb99a2ca1cf" + ], + [] + ] + }, + { + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, + "wires": [ + [ + "1eef47e0074545a9" + ] + ] + }, + { + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", + "name": "", + "x": 670, + "y": 1020, + "wires": [] + }, + { + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, + "wires": [] + }, + { + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, + "wires": [ + [ + "85ad07b8f973bbe2" + ] + ] + }, + { + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "endstop_angle", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2020, + "wires": [] + }, + { + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, + "wires": [ + [] + ] + }, + { + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, + "wires": [ + [ + "6b7245c3dcb694c8" + ] + ] + }, + { + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, + "wires": [ + [ + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" + ] + ] + }, + { + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, + "wires": [ + [ + "253feafa5a2f8b1d" + ] + ] + }, + { + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, + "wires": [ + [] + ] + }, + { + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_enable_endstop", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 1980, + "wires": [ + [ + "69516440e3997111", + "f036424d79645761" + ] + ] + }, + { + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, + "wires": [ + [ + "eefed04c25e3e4d6" + ] + ] + }, + { + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, + "wires": [ + [ + "2aaf7c7f0f0c146f" + ] + ] + }, + { + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", + "outputs": 1, + "x": 660, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3560, + "wires": [ + [ + "d0a1a4947a1137ca" + ] + ] + }, + { + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 520, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] + }, + { + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, + "wires": [ + [] + ] + }, + { + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3640, + "wires": [ + [ + "b5aba11033c5f952" + ] + ] + }, + { + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, + { + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "e98c1b83744bb863", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Delete Aborted", + "tooltip": "Delete aborted photosets", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 420, + "y": 520, + "wires": [ + [ + "7438a5bf5fcddec4" + ] + ] + }, + { + "id": "7438a5bf5fcddec4", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "delete_aborted", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('delete_aborted'):\n save('delete_aborted', state)\n", + "outputs": 1, + "x": 600, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "53681e53353db898", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'delete_aborted'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 520, + "wires": [ + [ + "e98c1b83744bb863" + ] + ] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'stable'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, + "wires": [ + [ + "e23c514008cad1a1" + ] + ] + }, + { + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] + }, + { + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, + "wires": [ + [ + "4ce127c61c3c5966", + "beacc3dc5398fa79" + ] + ] + }, + { + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", + "outputs": 1, + "x": 290, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "beacc3dc5398fa79", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "e23c514008cad1a1", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 480, + "y": 140, + "wires": [] + }, + { + "id": "b0629875a30ae1d7", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", + "outputs": 2, + "x": 390, + "y": 540, + "wires": [ + [ + "1bbe2d769f42c313" + ], + [ + "fefe45404bdb19c4" + ] + ] + }, + { + "id": "c7b6d05a62172432", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Status:", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 210, + "y": 400, + "wires": [] + }, + { + "id": "fefe45404bdb19c4", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "check files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "outputs": 1, + "x": 550, + "y": 560, + "wires": [ + [ + "1bbe2d769f42c313", + "ae92a328af306ebb" + ] + ] + }, + { + "id": "d0104e0163745993", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 115, + "y": 440, + "wires": [ + [ + "ec30638407332e43", + "38cbf7965d1c1834", + "49f1ecb29a3f84f4" + ] + ] + }, + { + "id": "ec30638407332e43", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadS", + "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 480, + "wires": [ + [ + "2852023f3aa8db10" + ] + ] + }, + { + "id": "2852023f3aa8db10", + "type": "ui_dropdown", + "z": "a5557543ccff5889", + "name": "", + "label": "", + "tooltip": "", + "place": "Select option", + "group": "ddbd496e.93a288", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "stable", + "value": "stable", + "type": "str" + }, + { + "label": "beta", + "value": "beta", + "type": "str" + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" + } + ], + "payload": "", + "topic": "topic", + "topicType": "msg", + "className": "", + "x": 340, + "y": 480, + "wires": [ + [ + "1e10b387ee30c486" + ] + ] + }, + { + "id": "1e10b387ee30c486", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "274129c51b0b87ef", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 4, + "width": 4, + "height": 1, + "name": "", + "label": "Updatetype: ", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 610, + "y": 480, + "wires": [] + }, + { + "id": "51cd8c8643e6b46a", + "type": "ui_switch", + "z": "a5557543ccff5889", + "name": "", + "label": "Auto-check update availability", + "tooltip": "", + "group": "ddbd496e.93a288", + "order": 6, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 410, + "y": 440, + "wires": [ + [ + "1ab4c6b4b232a022" + ] + ] + }, + { + "id": "38cbf7965d1c1834", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 440, + "wires": [ + [ + "51cd8c8643e6b46a" + ] + ] + }, + { + "id": "1ab4c6b4b232a022", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 610, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "ae92a328af306ebb", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "NO", + "cancel": "YES", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 710, + "y": 560, + "wires": [ + [ + "2de63e8e3ae5fb0c", + "929281fef53e09f8" + ] + ] + }, + { + "id": "cbd0afc4aa7b302a", + "type": "link in", + "z": "a5557543ccff5889", + "name": "update status", + "links": [ + "1bbe2d769f42c313", + "42061b28cff81f99" + ], + "x": 115, + "y": 400, + "wires": [ + [ + "c7b6d05a62172432", + "c94623ddd9d95f78" + ] + ] + }, + { + "id": "1bbe2d769f42c313", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 665, + "y": 520, + "wires": [] + }, + { + "id": "7cf60615d93e696b", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 7, + "width": 6, + "height": 1, + "passthru": false, + "label": "Check Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 180, + "y": 560, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "2de63e8e3ae5fb0c", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "download files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "outputs": 1, + "x": 880, + "y": 560, + "wires": [ + [ + "42061b28cff81f99", + "fe3a855fee9e28c6" + ] + ] + }, + { + "id": "929281fef53e09f8", + "type": "function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 850, + "y": 520, + "wires": [ + [ + "42061b28cff81f99" + ] + ] + }, + { + "id": "42061b28cff81f99", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 995, + "y": 520, + "wires": [] + }, + { + "id": "49f1ecb29a3f84f4", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 520, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "fe3a855fee9e28c6", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "9bb0adbd716ce347", + "01c882fcc51b349c" + ], + "x": 995, + "y": 560, + "wires": [] + }, + { + "id": "5e7d5e4335d37794", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 95, + "y": 700, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "2bb5fe78e09fec8a", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", + "outputs": 1, + "x": 210, + "y": 700, + "wires": [ + [ + "dbc77052ac950624", + "d97c3068ef5fef96", + "73a3b828f862312b", + "901e31453b2bdff8", + "f983854748ee4763", + "5347c7c517f5e8c7", + "3a5016f7003cd72c", + "6d720c4a4ecd9475", + "6438b7d060a70d81" + ] + ] + }, + { + "id": "d97c3068ef5fef96", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "OS:", + "format": "{{msg.os}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 740, + "wires": [] + }, + { + "id": "73a3b828f862312b", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 8, + "width": 0, + "height": 0, + "name": "", + "label": "Flask:", + "format": "{{msg.flask}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 780, + "wires": [] + }, + { + "id": "dbc77052ac950624", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Device:", + "format": "{{msg.device}}", + "layout": "row-spread", + "className": "", + "x": 500, + "y": 700, + "wires": [] + }, + { + "id": "3f42560297fe6978", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "name": "Download LOG", + "order": 9, + "width": 6, + "height": 1, + "format": "\n
Download error log\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 180, + "y": 1060, + "wires": [ + [] + ] + }, + { + "id": "c94623ddd9d95f78", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", + "outputs": 1, + "x": 210, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "39a502b38837273d", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "1e7457ea9c2c5e09" + ], + "x": 245, + "y": 600, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "901e31453b2bdff8", + "type": "delay", + "z": "a5557543ccff5889", + "name": "", + "pauseType": "delay", + "timeout": "10", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 220, + "y": 740, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "f983854748ee4763", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "", + "format": "{{msg.osdate}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 820, + "wires": [] + }, + { + "id": "5347c7c517f5e8c7", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "CPU temp:", + "format": "{{msg.temp}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 860, + "wires": [] + }, + { + "id": "3a5016f7003cd72c", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "CPU memory:", + "format": "{{msg.cpu}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 900, + "wires": [] + }, + { + "id": "6d720c4a4ecd9475", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 6, + "width": 0, + "height": 0, + "name": "", + "label": "Swap memory:", + "format": "{{msg.swap}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 940, + "wires": [] + }, + { + "id": "6438b7d060a70d81", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 7, + "width": 0, + "height": 0, + "name": "", + "label": "Diskspace:", + "format": "{{msg.diskspace}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 980, + "wires": [] + }, + { + "id": "8d012912f302be85", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 8, + "width": 6, + "height": 1, + "passthru": false, + "label": "Show Details/Changelog", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 210, + "y": 640, + "wires": [ + [ + "5242607a723cc628" + ] + ] + }, + { + "id": "5242607a723cc628", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "Changelog", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "outputs": 1, + "x": 430, + "y": 640, + "wires": [ + [ + "573722197b15bf84" + ] + ] + }, + { + "id": "573722197b15bf84", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 640, + "wires": [ + [] + ] + }, + { + "id": "9b3e6a06c82a0f52", + "type": "link in", + "z": "87715429b0b1c9a3", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 115, + "y": 420, + "wires": [ + [ + "f128ca405d1e1e4d", + "07d7ce3dab5f1c11" + ] + ] + }, + { + "id": "cd0dc08fcb5968c8", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Successful Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 425, + "y": 407, + "wires": [] + }, + { + "id": "f128ca405d1e1e4d", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics.csv|grep -vi false|tail -n +2|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Successful Scans", + "x": 250, + "y": 420, + "wires": [ + [ + "cd0dc08fcb5968c8" + ], + [], + [] + ] + }, + { + "id": "b91b4d65f2090793", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Aborted Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 440, + "y": 340, + "wires": [] + }, + { + "id": "07d7ce3dab5f1c11", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics.csv|grep -vi True|tail -n +2|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Aborted Scans", + "x": 245, + "y": 353, + "wires": [ + [ + "b91b4d65f2090793" + ], + [], + [] + ] + } +] \ No newline at end of file diff --git a/update/betaArdu/settings.js b/update/2024-11S/beta/settings.js similarity index 99% rename from update/betaArdu/settings.js rename to update/2024-11S/beta/settings.js index 41082c3..357b02b 100644 --- a/update/betaArdu/settings.js +++ b/update/2024-11S/beta/settings.js @@ -19,6 +19,7 @@ * - Node Settings * **/ +process.env.HOSTNAME = require('os').hostname(); module.exports = { diff --git a/update/2024-11S/beta/startup.sh b/update/2024-11S/beta/startup.sh new file mode 100755 index 0000000..bdaad1d --- /dev/null +++ b/update/2024-11S/beta/startup.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +settings_folder="/home/pi/OpenScan/settings" + +# Generate an unique UUID that identifies that OpenScan + +if [ ! -f $settings_folder/openscan_uuid ]; then + echo $(cat /proc/sys/kernel/random/uuid) > $settings_folder/openscan_uuid +fi +echo `cat /proc/cpuinfo|grep Model|cut -d: -f2|awk '{$1=$1};1'` > $settings_folder/architecture +echo `libcamera-still --list-cameras|head -3|tail -1|cut -d: -f2|cut -d[ -f1|awk '{$1=$1};1'` > $settings_folder/camera diff --git a/update/main/OpenScan.py b/update/2024-11S/meanwhile/OpenScan.py similarity index 59% rename from update/main/OpenScan.py rename to update/2024-11S/meanwhile/OpenScan.py index b1b994a..e634511 100644 --- a/update/main/OpenScan.py +++ b/update/2024-11S/meanwhile/OpenScan.py @@ -1,5 +1,6 @@ basepath = '/home/pi/OpenScan/' from os.path import isfile +import os def load_bool(name): filename = basepath+'settings/'+name @@ -13,6 +14,72 @@ def load_bool(name): value = False return value +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + return True + def load_str(name): filename = basepath+'settings/'+name if not isfile(filename): @@ -64,12 +131,12 @@ def camera(cmd, msg = {}): except: return 400 -def motorrun(motor,angle): +def motorrun(motor,angle,ES_enable=False,ES_start_state = True): + #motor can be "rotor", "tt" or "extra" import RPi.GPIO as GPIO from time import sleep from math import cos msg = {'cmd':'set'} - camera('/ping', msg) GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) @@ -77,6 +144,7 @@ def motorrun(motor,angle): spr = load_int(motor + '_stepsperrotation') dirpin = load_int('pin_' + motor + '_dir') steppin = load_int('pin_' + motor +'_step') + ES_pin = load_int('pin_' + motor + '_endstop') dir = load_int(motor + '_dir') ramp = load_int(motor + '_accramp') acc = load_float(motor + '_acc') @@ -86,12 +154,23 @@ def motorrun(motor,angle): step_count=int(angle*spr/360) * dir GPIO.setup(dirpin, GPIO.OUT) GPIO.setup(steppin, GPIO.OUT) + GPIO.setup(ES_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP) + if (step_count>0): GPIO.output(dirpin, GPIO.HIGH) if(step_count<0): GPIO.output(dirpin, GPIO.LOW) step_count=-step_count for x in range(step_count): + if ES_enable == True and GPIO.input(ES_pin) != ES_start_state: + i = 0 + while i <= 10: + if GPIO.input(ES_pin) == ES_start_state: + i = 11 + if i == 10: + return + i = i + 1 + GPIO.output(steppin, GPIO.HIGH) if x<=ramp and x<=step_count/2: delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) @@ -108,7 +187,6 @@ def motorrun(motor,angle): def ringlight(number,state): import RPi.GPIO as GPIO msg = {'cmd':'set'} - camera('/ping', msg) pin = load_int('pin_ringlight' + str(number)) GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) @@ -121,8 +199,6 @@ def take_photo(file): model=load_str('model') - - shutter = str(load_int('cam_shutter')) saturation = load_str('cam_saturation') contrast = load_str('cam_contrast') @@ -195,3 +271,42 @@ def create_coordinates(angle_min, angle_max,point_count): point_count=point_count+1 return filtered + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/2024-11S/meanwhile/OpenScanStatistics.py b/update/2024-11S/meanwhile/OpenScanStatistics.py new file mode 100755 index 0000000..68005af --- /dev/null +++ b/update/2024-11S/meanwhile/OpenScanStatistics.py @@ -0,0 +1,18 @@ +import csv + +class ScanStatistics: + def __init__(self, filename="/home/pi/OpenScan/statistics/statistics.csv"): + self.filename = filename + self.header = ["arch", "shield", "date_init", "date_end", "num_photos", "done-photos", "camera", "aborted"] + + def write_statistics(self, arch, shield, date_init, date_end, num_photos, done_photos, camera, aborted): + data = [arch, shield, date_init, date_end, num_photos, done_photos, camera, aborted] + + with open(self.filename, "a", newline='') as csv_file: + csv_writer = csv.writer(csv_file, delimiter=';') + + # Write header if file is empty + if csv_file.tell() == 0: + csv_writer.writerow(self.header) + + csv_writer.writerow(data) diff --git a/update/2024-11S/meanwhile/config.txt b/update/2024-11S/meanwhile/config.txt new file mode 100755 index 0000000..3bb8fef --- /dev/null +++ b/update/2024-11S/meanwhile/config.txt @@ -0,0 +1,34 @@ +# For more options and information see +# http://rpf.io/configtxt +# Some settings may impact device functionality. See link above for details + +# Additional overlays and parameters are documented /boot/overlays/README + +# Automatically load overlays for detected cameras +camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[pi4] +# Run as fast as firmware / board allows +arm_boost=1 +dtoverlay=imx519,cma-512 + +[all] +camera_auto_detect=0 +gpu_mem=256 +dtoverlay=imx519 \ No newline at end of file diff --git a/update/2024-11S/meanwhile/expand_root.sh b/update/2024-11S/meanwhile/expand_root.sh new file mode 100755 index 0000000..f4f7148 --- /dev/null +++ b/update/2024-11S/meanwhile/expand_root.sh @@ -0,0 +1,7 @@ +#!/bin/bash +if test -f "/boot/expand_root"; then + echo "expanding root partition" + raspi-config --expand-rootfs + rm -fr /boot/expand_root + shutdown -r now +fi diff --git a/update/2024-11S/meanwhile/fla.py b/update/2024-11S/meanwhile/fla.py new file mode 100644 index 0000000..026867e --- /dev/null +++ b/update/2024-11S/meanwhile/fla.py @@ -0,0 +1,519 @@ +from flask import Flask, request, redirect, send_file, send_from_directory +from flask_restx import Resource, Api, Namespace +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont +from time import sleep, time +from OpenScan import load_int, load_float, load_bool, ringlight, motorrun +import RPi.GPIO as GPIO +from math import sqrt +import os +import math +from skimage import feature, color, transform +import numpy as np +from scipy import ndimage +import socket + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +app = Flask(__name__) +api = Api(app, version='1.0', title='OpenScan API', description='API for OpenScan') + +v1 = Namespace('v1', description='API v1') +# Create a namespace for system operations +system_ns = Namespace('system', description='System operations') +camera_ns = Namespace('camera', description='Camera operations') +motor_ns = Namespace('motor', description='Motor operations') + +api.add_namespace(v1, path='/v1') +api.add_namespace(system_ns, path='/v1/system') +api.add_namespace(camera_ns, path='/v1/camera') +api.add_namespace(motor_ns, path='/v1/motor') + +basedir = '/home/pi/OpenScan/' +timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + + +################################################################################################################### + + +@system_ns.route('/status') +class Status(Resource): + def get(self): + ''' + Get system status + ''' + import os + import json + from time import time + + if os.path.exists('/tmp/status.json'): + try: + with open('/tmp/status.json', 'r') as status_file: + status = json.load(status_file) + + elapsed_time = time() - status['start_time'] + estimated_total_time = (elapsed_time / status['current_photo']) * status['total_photos'] + time_remaining = max(0, estimated_total_time - elapsed_time) + + status.update({ + "status": "running", + "elapsed_time": int(elapsed_time), + "estimated_total_time": int(estimated_total_time), + "time_remaining": int(time_remaining) + }) + + return status, 200 + except Exception as e: + return {"error": f"Error reading status file: {str(e)}"}, 500 + else: + return {"status": "idle"}, 200 + +@system_ns.route('/shutdown') +class Shutdown(Resource): + @system_ns.doc(params={'token': 'Shutdown token for authentication'}) + def get(self): + '''Shutdown the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('shutdown -h now') + return {'message': 'Shutting down'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/reboot') +class Reboot(Resource): + @system_ns.doc(params={'token': 'Reboot token for authentication'}) + def get(self): + '''Reboot the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('reboot -h') + return {'message': 'Rebooting'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/ringlight') +class Ringlight(Resource): + @system_ns.doc(params={'state': 'Ringlight state (0 or 1)'}) + def get(self): + '''Set ringlight state''' + state = int(request.args.get('state')) + if state == 0: + ringlight(1, False) + ringlight(2, False) + else: + ringlight(1, True) + ringlight(2, True) + return {'message': f'Ringlight set to {state}'}, 200 + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) + + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') + + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wait 3-5s + return {'message': 'Auto focus triggered'}, 200 + +@motor_ns.route('/motor_run') +class MotorRun(Resource): + ''' + Run a motor + ''' + @motor_ns.doc(params={ + 'motor': 'Motor name (rotor, tt, extra)', + 'angle': 'Angle to rotate (integer)', + 'ES_enable': 'Enable endstop (optional, boolean)', + 'ES_start_state': 'Endstop start state (optional, boolean)' + }) + @motor_ns.response(400, 'Bad Request') + def get(self): + '''Run a motor''' + motor = request.args.get('motor') + if not motor: + return {'error': 'Motor parameter is required'}, 400 + if motor not in ['rotor', 'tt', 'extra']: + return {'error': 'Invalid motor name'}, 400 + + try: + angle = int(request.args.get('angle')) + except (TypeError, ValueError): + return {'error': 'Angle must be an integer'}, 400 + + ES_enable = request.args.get('ES_enable', 'false').lower() == 'true' + ES_start_state = request.args.get('ES_start_state', 'true').lower() == 'true' + + try: + motorrun(motor, angle, ES_enable, ES_start_state) + except Exception as e: + return {'error': f'Error running motor: {str(e)}'}, 500 + + return {'message': f'Motor {motor} run to {angle} degrees'}, 200 + + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + + +if __name__ == '__main__': +# app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) + app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) + diff --git a/update/2024-11S/meanwhile/flows.json b/update/2024-11S/meanwhile/flows.json new file mode 100644 index 0000000..e2e8c61 --- /dev/null +++ b/update/2024-11S/meanwhile/flows.json @@ -0,0 +1,9778 @@ +[ + { + "id": "e6f4d02efb300ea9", + "type": "tab", + "label": "Init", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "481edaf6db5a7a54", + "type": "tab", + "label": "Scan", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "80a3942785a26c29", + "type": "tab", + "label": "Files", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "e43a27722b508115", + "type": "tab", + "label": "Settings", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "a5557543ccff5889", + "type": "tab", + "label": "Update", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "87715429b0b1c9a3", + "type": "tab", + "label": "Statistics", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", + "type": "ui_tab", + "name": "Scan", + "icon": "dashboard", + "order": 2, + "disabled": false, + "hidden": false + }, + { + "id": "5c06cb6bcc371ee6", + "type": "ui_base", + "theme": { + "name": "theme-dark", + "lightTheme": { + "default": "#0094CE", + "baseColor": "#0094CE", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "darkTheme": { + "default": "#097479", + "baseColor": "#097479", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "customTheme": { + "name": "Untitled Theme 1", + "default": "#4B7930", + "baseColor": "#4B7930", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false + }, + "themeState": { + "base-color": { + "default": "#097479", + "value": "#097479", + "edited": false + }, + "page-titlebar-backgroundColor": { + "value": "#097479", + "edited": false + }, + "page-backgroundColor": { + "value": "#111111", + "edited": false + }, + "page-sidebar-backgroundColor": { + "value": "#333333", + "edited": false + }, + "group-textColor": { + "value": "#0eb8c0", + "edited": false + }, + "group-borderColor": { + "value": "#555555", + "edited": false + }, + "group-backgroundColor": { + "value": "#333333", + "edited": false + }, + "widget-textColor": { + "value": "#eeeeee", + "edited": false + }, + "widget-backgroundColor": { + "value": "#097479", + "edited": false + }, + "widget-borderColor": { + "value": "#333333", + "edited": false + }, + "base-font": { + "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + } + }, + "angularTheme": { + "primary": "indigo", + "accents": "blue", + "warn": "red", + "background": "grey", + "palette": "light" + } + }, + "site": { + "name": "OpenScan", + "hideToolbar": "false", + "allowSwipe": "false", + "lockMenu": "false", + "allowTempTheme": "true", + "dateFormat": "DD/MM/YYYY", + "sizes": { + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, + "cx": 6, + "cy": 6, + "px": 0, + "py": 0 + } + } + }, + { + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 8 + }, + { + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 7 + }, + { + "id": "b5fdd57b.15eda8", + "type": "ui_group", + "name": "Main", + "tab": "15a222ed.d70a7d", + "order": 1, + "disp": false, + "width": 13, + "collapse": false + }, + { + "id": "db43d646.2074c8", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", + "order": 2, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "15a222ed.d70a7d", + "type": "ui_tab", + "name": "Files&Cloud", + "icon": "dashboard", + "order": 3, + "disabled": false, + "hidden": false + }, + { + "id": "365a30d0dfa83e95", + "type": "ui_group", + "name": "settings", + "tab": "e23b837a9f040895", + "order": 1, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "ac7409105cfecac6", + "type": "ui_group", + "name": "advanced", + "tab": "e23b837a9f040895", + "order": 3, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "729f9ea6e3513c9b", + "type": "ui_group", + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "5b3e5aca21140e9a", + "type": "ui_group", + "name": "Update", + "tab": "b3150b13e34b1fe8", + "order": 1, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "b3150b13e34b1fe8", + "type": "ui_tab", + "name": "OpenScan", + "icon": "dashboard", + "order": 1, + "disabled": false, + "hidden": true + }, + { + "id": "ddbd496e.93a288", + "type": "ui_group", + "name": "Manage Updates", + "tab": "d25e08b4.5b27e8", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "3ce32450.e0cffc", + "type": "ui_group", + "name": "System & Stats", + "tab": "d25e08b4.5b27e8", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "d25e08b4.5b27e8", + "type": "ui_tab", + "name": "Update & Info", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "4390b2ebcbbe104c", + "type": "ui_group", + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "8ab79a98e536e0d6", + "type": "ui_group", + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Motor", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 5, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 1, + "width": 1, + "height": 1 + }, + { + "id": "33b6d7317d1524b8", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "aaf5b874c52a58aa", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, + "height": 1 + }, + { + "id": "f8d8740dcbf499fb", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 11, + "width": 1, + "height": 1 + }, + { + "id": "7ac0cb556740d159", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, + "height": 1 + }, + { + "id": "4de2414e29020c74", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "90223f7ddc082321", + "order": 2, + "width": 7, + "height": 1 + }, + { + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 + }, + { + "id": "ce21673092264c38", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, + "height": 1 + }, + { + "id": "3f7b77f8a1675d27", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "12b719cba49817c9", + "order": 7, + "width": 4, + "height": 1 + }, + { + "id": "0799b02d12fc3a14", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "7a3279eea439bcdd", + "order": 25, + "width": 6, + "height": 1 + }, + { + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 8, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "ac59b8fb186de073", + "type": "ui_group", + "name": "Statistics", + "tab": "656b4eb8b15dab8f", + "order": 3, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "656b4eb8b15dab8f", + "type": "ui_tab", + "name": "Statistics", + "icon": "dashboard", + "order": 6, + "disabled": false, + "hidden": false + }, + { + "id": "0b244f698c7ac9a2", + "type": "ui_group", + "name": "Shield Type", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "e357ef02.ef3cb", + "type": "ui_group", + "name": "Page 1", + "tab": "4bc17c6e.b74934", + "order": 2, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "c9165343995892c6", + "type": "ui_group", + "name": "Page 2", + "tab": "", + "order": 1, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "4bc17c6e.b74934", + "type": "ui_tab", + "name": "Page 1", + "icon": "wi-wu-tstorms", + "order": 5, + "disabled": false, + "hidden": false + }, + { + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 520, + "wires": [ + [ + "949bafced17d66d6" + ] + ] + }, + { + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "a1f0ed7d5a9d670e", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.1", + "topic": "", + "x": 110, + "y": 60, + "wires": [ + [ + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6", + "d81572486f15cd7a" + ] + ] + }, + { + "id": "544d20f02215011a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 60, + "wires": [ + [ + "c77552216a8bb781" + ] + ] + }, + { + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 540, + "y": 60, + "wires": [ + [ + "960912e90ba5b5bc" + ] + ] + }, + { + "id": "960912e90ba5b5bc", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244", + "9b3e6a06c82a0f52", + "fbc5fc2e65311f8b" + ], + "x": 645, + "y": 60, + "wires": [] + }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "168d72a54504b327", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "5/0.1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "5", + "topic": "", + "payload": "", + "payloadType": "str", + "x": 100, + "y": 440, + "wires": [ + [ + "6c6ef2255a7d39e5" + ] + ] + }, + { + "id": "6c6ef2255a7d39e5", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "repeat 5s/0.1s", + "mode": "link", + "links": [ + "61990987acd0f263", + "2415272f42ce468c", + "6bf8344af427a6ba" + ], + "x": 205, + "y": 440, + "wires": [] + }, + { + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", + "outputs": 1, + "x": 270, + "y": 140, + "wires": [ + [ + "eb1a2387a1eeea76" + ] + ] + }, + { + "id": "b1e2491c952f84c9", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, + "wires": [ + [ + "200d4b9951b6e066" + ] + ] + }, + { + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "65518f3d4e3095e5", + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 800, + "y": 40, + "wires": [ + [ + "544d20f02215011a" + ] + ] + }, + { + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 650, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", + "outputs": 1, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 600, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 680, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 640, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 720, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "8955d11554f55e63", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "5b3e5aca21140e9a", + "order": 1, + "width": 6, + "height": 3, + "passthru": false, + "label": "Install Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "date", + "topic": "", + "topicType": "str", + "x": 120, + "y": 820, + "wires": [ + [ + "1e7457ea9c2c5e09" + ] + ] + }, + { + "id": "1e7457ea9c2c5e09", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "update", + "mode": "link", + "links": [ + "39a502b38837273d" + ], + "x": 245, + "y": 820, + "wires": [] + }, + { + "id": "245e4341d4fb611c", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 790, + "y": 540, + "wires": [ + [ + "627406f3611511dc" + ] + ] + }, + { + "id": "627406f3611511dc", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "write", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 930, + "y": 540, + "wires": [ + [ + "50eeb3e362f9027f" + ] + ] + }, + { + "id": "88b1bddde110298a", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 650, + "y": 540, + "wires": [ + [ + "245e4341d4fb611c" + ] + ] + }, + { + "id": "50eeb3e362f9027f", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "1dffb799fdf10cbc", + "2afb6a45c73fa244", + "2e9b29c70969cf01", + "2f4c0f98.dee2", + "3876d5cbd248592b", + "592ec13d8f8923a9", + "5e7d5e4335d37794", + "9b3e6a06c82a0f52", + "9fd259de91de1da1", + "b4c843620c251c43", + "cb40b9341bd22a28", + "d0104e0163745993", + "d1efcd5fa9d25785", + "da61581182b7299e", + "e5f38b4a07a5e278", + "fbc5fc2e65311f8b", + "fd0258418489839d" + ], + "x": 1015, + "y": 540, + "wires": [] + }, + { + "id": "4f3121f158f06a61", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", + "outputs": 1, + "x": 860, + "y": 580, + "wires": [ + [] + ] + }, + { + "id": "4a8a04b1e5dca8fe", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "run rotor till endstop", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 690, + "y": 580, + "wires": [ + [ + "4f3121f158f06a61" + ] + ] + }, + { + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n
    \n
  • speed improvement 2-3x
  • \n
  • currently tested on OpenScan Mini + IMX519 with RPi 4
  • \n
  • optimized toolpath
  • \n
  • more responsive user interface
  • \n
  • hotspot mode (when no wireless network available ssid: openscan pw: opensource
  • \n
  • preview features and sharpness
  • \n
  • partial background masking
  • \n
  • no more autofocus --> instead you can set a min and max focus distance
  • \n
\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 580, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "e548168473aa85d6", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 5, + "width": 0, + "height": 0, + "passthru": false, + "label": "Statistics", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "5", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 100, + "y": 760, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "d81572486f15cd7a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "loadl", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'openscan_version'\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.payload = String(data);\nflow.set('openscan_version',data)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 360, + "wires": [ + [ + "b1b0ccb783dd5882" + ] + ] + }, + { + "id": "fa6db57803ae2b6d", + "type": "debug", + "z": "e6f4d02efb300ea9", + "name": "debug 7", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 590, + "y": 460, + "wires": [] + }, + { + "id": "b1b0ccb783dd5882", + "type": "change", + "z": "e6f4d02efb300ea9", + "name": "openscan_version", + "rules": [ + { + "t": "set", + "p": "openscan_version", + "pt": "flow", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 415, + "y": 360, + "wires": [ + [ + "fa6db57803ae2b6d", + "0d8c6bc7887fb3c2" + ] + ] + }, + { + "id": "6a3d9acbe097a3d2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 120, + "wires": [ + [ + "cb6ebdabaaf7d0da" + ] + ] + }, + { + "id": "7ef6f1b5c67201fe", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "86f7d1b2d763f6e2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 160, + "wires": [ + [ + "c8a3fde5206ce1ae" + ] + ] + }, + { + "id": "fd799c931139764d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 240, + "wires": [ + [ + "87be854db758a9a6" + ] + ] + }, + { + "id": "d5140d455122c49a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 280, + "wires": [ + [ + "9daea4bd57f7a00e" + ] + ] + }, + { + "id": "194f3590dd4f6e3d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "2de69452e829d780", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", + "label": "", + "tooltip": "", + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, + "height": 1, + "passthru": true, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 320, + "y": 80, + "wires": [ + [ + "734ac3bff2df6837" + ] + ] + }, + { + "id": "97170908e1f4ac55", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 80, + "wires": [ + [ + "58e565fea35cb667" + ] + ] + }, + { + "id": "734ac3bff2df6837", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 55, + "y": 80, + "wires": [ + [ + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" + ] + ] + }, + { + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/v1/camera/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", + "outputs": 1, + "x": 510, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "c7f5808d753480d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 170, + "y": 200, + "wires": [ + [ + "11f41a6030578ef4" + ] + ] + }, + { + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 200, + "wires": [ + [ + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "855cbcadef1163c5", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 840, + "wires": [ + [ + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" + ] + ] + }, + { + "id": "1a443e20a973d2f1", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw true", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 630, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "d1b87196ae5373ed", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw false", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 430, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "03d92601c62b79d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "4s/0.5", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "Repeat", + "payload": "0.1", + "payloadType": "str", + "x": 100, + "y": 840, + "wires": [ + [ + "855cbcadef1163c5" + ] + ] + }, + { + "id": "41e6a4649b6afbfb", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Take Preview Shot", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/v1/camera/picam2_take_photo')\n\nreturn msg\n", + "outputs": 1, + "x": 450, + "y": 800, + "wires": [ + [ + "1a443e20a973d2f1", + "296636b7467fc745" + ] + ] + }, + { + "id": "85a268108250ba88", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", + "order": 1, + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 450, + "y": 840, + "wires": [ + [ + "417f653ca0dfdcfc", + "180476141c2a44ad" + ] + ] + }, + { + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, + "wires": [] + }, + { + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, + "wires": [ + [ + "e864254b18c23dd1" + ] + ] + }, + { + "id": "e864254b18c23dd1", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int\n\nif 'payload' not in msg:\n return\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'))\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'))\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'))\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'))\n\n", + "outputs": 1, + "x": 780, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "180476141c2a44ad", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 880, + "wires": [ + [ + "8cbdbfecbd12ef83" + ] + ] + }, + { + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", + "outputs": 1, + "x": 870, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", + "outputs": 1, + "x": 440, + "y": 720, + "wires": [ + [ + "923be3b2b25224b4" + ] + ] + }, + { + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "c8a3fde5206ce1ae", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 160, + "wires": [ + [ + "034ec9f59e50a361", + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "034ec9f59e50a361", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, + "wires": [ + [ + "194f3590dd4f6e3d" + ] + ] + }, + { + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, + "wires": [ + [ + "2de69452e829d780" + ] + ] + }, + { + "id": "cb6ebdabaaf7d0da", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 120, + "wires": [ + [ + "7ef6f1b5c67201fe" + ] + ] + }, + { + "id": "82ecd3cd971cb7ea", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, + "height": 1, + "name": "projectname", + "label": "Projectname", + "format": "", + "layout": "row-left", + "className": "", + "x": 530, + "y": 40, + "wires": [] + }, + { + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, + "wires": [ + [ + "06e1e19835a9816e" + ] + ] + }, + { + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, + "wires": [ + [ + "1fe18f3b0b52aabd" + ] + ] + }, + { + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "7dd287f40385922f", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "start ", + "group": "365a30d0dfa83e95", + "order": 10, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-play", + "payload": "", + "payloadType": "date", + "topic": "enabled", + "topicType": "str", + "x": 130, + "y": 1040, + "wires": [ + [ + "33d94a04b96a2de0", + "6d15f717d5a11002", + "9a6b30a0175a8ecd" + ] + ] + }, + { + "id": "579f2211199fd6ab", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "stop", + "group": "365a30d0dfa83e95", + "order": 12, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-stop", + "payload": "numberofphotos", + "payloadType": "global", + "topic": "", + "topicType": "str", + "x": 490, + "y": 1100, + "wires": [ + [ + "1787f08ed7070ddd", + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "1787f08ed7070ddd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "stop", + "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "outputs": 1, + "x": 630, + "y": 1100, + "wires": [ + [] + ] + }, + { + "id": "e9b13dfd9f8d3711", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 395, + "y": 1000, + "wires": [] + }, + { + "id": "9654deebb668e012", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "1s", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 290, + "y": 1140, + "wires": [ + [ + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "8367cfa0bf5bc5df", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine", + "links": [ + "200d4b9951b6e066", + "8689e938.dd9e38", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 45, + "y": 1040, + "wires": [ + [ + "7dd287f40385922f" + ] + ] + }, + { + "id": "fb13752beddee9f2", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 535, + "y": 1060, + "wires": [] + }, + { + "id": "33d94a04b96a2de0", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1100, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "c1c044f3c2139f68", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 1140, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "1daf9e3a5bd5ab48", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 430, + "y": 1040, + "wires": [ + [ + "fb13752beddee9f2" + ] + ] + }, + { + "id": "6d15f717d5a11002", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 1000, + "wires": [ + [ + "e9b13dfd9f8d3711" + ] + ] + }, + { + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "# The contents of this file are embedded in the OpenScan app (Node-RED)\nfrom OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom OpenScanStatistics import ScanStatistics\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\nfrom datetime import datetime\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname, remove\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\nimport json\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\nstats = ScanStatistics()\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/v1/camera/picam2_switch_mode?mode=1')\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\narchitecture = load_str(\"architecture\")\ncamera_model = load_str(\"camera\")\nshield = load_str(\"shield_type\")\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\ndelete_aborted = load_bool('delete_aborted')\nif load_bool('rotor_enable_endstop'):\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True, False)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_current_timestamp():\n return datetime.now().strftime(\"%Y-%m-%d %H:%M\")\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/v1/camera/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/v1/camera/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n motorrun('rotor',rotor_angle)\n motorrun('tt',tt_angle)\n return\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/v1/camera/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\ncounter2 = 0\n\ndate_init = get_current_timestamp()\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\n\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n \n # Calculate time remaining and write status to /tmp/status as JSON\n elapsed_time = time() - starttime\n estimated_total_time = (elapsed_time / counter) * photocount * steps\n time_remaining = max(0, estimated_total_time - elapsed_time)\n \n status = {\n \"scan_name\": projectname,\n \"total_photos\": photocount,\n \"current_photo\": counter,\n \"stacksize\": steps,\n \"start_time\": int(starttime),\n }\n with open('/tmp/status.json', 'w') as status_file:\n json.dump(status, status_file)\n\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/v1/camera/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\ntry:\n remove('/tmp/status.json')\nexcept FileNotFoundError:\n pass # File doesn't exist, so no need to delete\nexcept Exception as e:\n print(f\"Error deleting /tmp/status.json: {e}\")\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\ndate_end = get_current_timestamp()\n\nif counter == photocount:\n stats.write_statistics(architecture, shield, date_init, date_end, photocount, counter, camera_model, False)\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\nelse:\n stats.write_statistics(architecture, shield, date_init, date_end, photocount, counter, camera_model, True)\n if delete_aborted:\n remove(zippath)\n else:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, + "wires": [ + [ + "1daf9e3a5bd5ab48", + "795c85ad4f109567" + ] + ] + }, + { + "id": "afe47a9eaae6f67f", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, + "height": 1, + "name": "", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", + "className": "", + "x": 340, + "y": 40, + "wires": [] + }, + { + "id": "8608517d0567d63f", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 40, + "wires": [ + [ + "afe47a9eaae6f67f" + ] + ] + }, + { + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 55, + "y": 40, + "wires": [ + [ + "8608517d0567d63f" + ] + ] + }, + { + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, + "wires": [ + [ + "9774e7ad3b506354" + ] + ] + }, + { + "id": "9774e7ad3b506354", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 380, + "wires": [ + [ + "f0af909f3e739b22" + ] + ] + }, + { + "id": "39c744466a21735e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 40, + "wires": [ + [ + "fa181d22775c2ce6" + ] + ] + }, + { + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 80, + "wires": [ + [ + "c615034ea6b26174" + ] + ] + }, + { + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 480, + "wires": [ + [ + "237c2135cdad86ea" + ] + ] + }, + { + "id": "dd7fb8791d34c751", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 880, + "wires": [ + [ + "180476141c2a44ad" + ] + ] + }, + { + "id": "5baf89a2682265f7", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "enable led", + "links": [ + "eb1a2387a1eeea76" + ], + "x": 145, + "y": 880, + "wires": [ + [ + "dd7fb8791d34c751" + ] + ] + }, + { + "id": "6a26e8a7253d708c", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 40, + "wires": [ + [ + "39c744466a21735e" + ] + ] + }, + { + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, + "wires": [ + [ + "61aab497fa50898e" + ] + ] + }, + { + "id": "9fd259de91de1da1", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 735, + "y": 40, + "wires": [ + [ + "6a26e8a7253d708c", + "35ad7e55833836c1" + ] + ] + }, + { + "id": "fa181d22775c2ce6", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 40, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "c615034ea6b26174", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 80, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "ae5ee8787145906d", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import camera\ncamera('/v1/camera/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", + "outputs": 1, + "x": 1290, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "f0af909f3e739b22", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Features", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 420, + "wires": [ + [ + "710fc2dbb5ef0167" + ] + ] + }, + { + "id": "710fc2dbb5ef0167", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "d93c2b67bcf23b9a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 480, + "wires": [ + [ + "5e83b653850fa16e" + ] + ] + }, + { + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 95, + "y": 480, + "wires": [ + [ + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" + ] + ] + }, + { + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "c8b93b42c720b9cf", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", + "links": [ + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" + ], + "x": 85, + "y": 380, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 620, + "y": 1000, + "wires": [] + }, + { + "id": "ea54fcc2.cfcc2", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "get dirs", + "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "outputs": 1, + "x": 480, + "y": 180, + "wires": [ + [ + "f3662f8c7d3d7a2d", + "01e4783e148c6698" + ] + ] + }, + { + "id": "2f4c0f98.dee2", + "type": "link in", + "z": "80a3942785a26c29", + "name": "filelist", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "a4f09e25.02569", + "ed35109311335099", + "fb13752beddee9f2" + ], + "x": 355, + "y": 220, + "wires": [ + [ + "ea54fcc2.cfcc2" + ] + ] + }, + { + "id": "952ce286.4ffd4", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 4, + "width": 6, + "height": 1, + "name": "Status", + "label": "Status", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 250, + "y": 60, + "wires": [] + }, + { + "id": "d4383424.7807c8", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "upload", + "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", + "outputs": 2, + "x": 530, + "y": 460, + "wires": [ + [ + "9a132ab1.b21658" + ], + [ + "3d16b3789632784d", + "9a132ab1.b21658" + ] + ] + }, + { + "id": "50710948.71c308", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "set", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 750, + "y": 180, + "wires": [ + [ + "ada1b6f7cccc9344", + "85839a17fb7b58b9" + ] + ] + }, + { + "id": "834046a4.647938", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 5, + "width": 6, + "height": 1, + "name": "Set", + "label": "Set:", + "format": "{{msg.payload.Name}}", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 220, + "wires": [] + }, + { + "id": "9a132ab1.b21658", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.true", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 780, + "y": 460, + "wires": [ + [ + "8689e938.dd9e38" + ] + ] + }, + { + "id": "3c67e97b.9d19a6", + "type": "function", + "z": "80a3942785a26c29", + "name": "enable", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 130, + "y": 340, + "wires": [ + [ + "7a93d1e18254685c", + "e434ef42bd6b92e8", + "d5d840183025d91b", + "ab9e90ab5a53a0dd", + "478994f671a3907d" + ] + ] + }, + { + "id": "bfc01f26.c32cf", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.false", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 500, + "wires": [ + [ + "f20f2dbc.0f123" + ] + ] + }, + { + "id": "b33d604c.5f1a6", + "type": "link in", + "z": "80a3942785a26c29", + "name": "enable cloud", + "links": [ + "4082b136.dae18", + "8689e938.dd9e38", + "bd75f33b8a57c522", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 35, + "y": 340, + "wires": [ + [ + "3c67e97b.9d19a6" + ] + ] + }, + { + "id": "f6bd1a04.470838", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "set", + "tot": "global" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 410, + "y": 460, + "wires": [ + [ + "d4383424.7807c8" + ] + ] + }, + { + "id": "4082b136.dae18", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "b33d604c.5f1a6", + "87574a42938afec4" + ], + "x": 715, + "y": 140, + "wires": [] + }, + { + "id": "f20f2dbc.0f123", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 515, + "y": 500, + "wires": [] + }, + { + "id": "8689e938.dd9e38", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 875, + "y": 460, + "wires": [] + }, + { + "id": "15de0ebb.616d61", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 380, + "wires": [ + [ + "a7d89487.ee8858" + ] + ] + }, + { + "id": "a7d89487.ee8858", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", + "outputs": 1, + "x": 690, + "y": 380, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "a4f09e25.02569", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2" + ], + "x": 775, + "y": 360, + "wires": [] + }, + { + "id": "7a93d1e18254685c", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "92c98e6ce7cd25f9" + ], + "x": 235, + "y": 500, + "wires": [] + }, + { + "id": "4d99c601c9881680", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "refresh", + "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", + "outputs": 2, + "x": 320, + "y": 180, + "wires": [ + [ + "ea54fcc2.cfcc2", + "b42e061fb1f1f3d7" + ], + [ + "6434e713f088012b" + ] + ] + }, + { + "id": "372e95797a3f2f3b", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "limit :)", + "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", + "outputs": 1, + "x": 90, + "y": 220, + "wires": [ + [ + "573edbfdb7500ddc" + ] + ] + }, + { + "id": "573edbfdb7500ddc", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 230, + "y": 220, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "dacb1f078b624e10", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 340, + "wires": [ + [ + "c8d65cc7c2ff7c36" + ] + ] + }, + { + "id": "92c98e6ce7cd25f9", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "7a93d1e18254685c", + "bd75f33b8a57c522" + ], + "x": 35, + "y": 180, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "3d16b3789632784d", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 770, + "y": 500, + "wires": [ + [] + ] + }, + { + "id": "6434e713f088012b", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 470, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "c8d65cc7c2ff7c36", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", + "outputs": 1, + "x": 690, + "y": 340, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "f4e9a4bd79b4221f", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 340, + "wires": [ + [ + "dacb1f078b624e10" + ] + ] + }, + { + "id": "2806bf08ea21216d", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 380, + "wires": [ + [ + "15de0ebb.616d61" + ] + ] + }, + { + "id": "61990987acd0f263", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 45, + "y": 60, + "wires": [ + [ + "51579603bce21e98" + ] + ] + }, + { + "id": "e8e488a6dd5d0b33", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "Download", + "order": 8, + "width": 3, + "height": 1, + "format": "\n
Download\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 880, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "0c387c0291d6c131", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 750, + "y": 260, + "wires": [ + [ + "e8e488a6dd5d0b33" + ] + ] + }, + { + "id": "e5f38b4a07a5e278", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 655, + "y": 220, + "wires": [ + [ + "834046a4.647938" + ] + ] + }, + { + "id": "e434ef42bd6b92e8", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "upload2", + "order": 7, + "width": 3, + "height": 1, + "format": "upload", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 460, + "wires": [ + [ + "f6bd1a04.470838" + ] + ] + }, + { + "id": "c46e10b9c201913e", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "refresh", + "order": 2, + "width": 4, + "height": 1, + "format": "refresh{{msg.text}}", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 160, + "y": 180, + "wires": [ + [ + "372e95797a3f2f3b", + "4d99c601c9881680" + ] + ] + }, + { + "id": "d5d840183025d91b", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del set", + "order": 11, + "width": 2, + "height": 1, + "format": "delete set", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 380, + "wires": [ + [ + "2806bf08ea21216d" + ] + ] + }, + { + "id": "ab9e90ab5a53a0dd", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del ", + "order": 10, + "width": 2, + "height": 1, + "format": "delete all", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 340, + "wires": [ + [ + "f4e9a4bd79b4221f" + ] + ] + }, + { + "id": "478994f671a3907d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "combine", + "order": 9, + "width": 2, + "height": 1, + "format": "combine", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 540, + "wires": [ + [ + "51bfd0fb7b1d292e" + ] + ] + }, + { + "id": "189c1eed09624a7b", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 580, + "wires": [ + [ + "1493398979a63775" + ] + ] + }, + { + "id": "51bfd0fb7b1d292e", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 420, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "da325be8e74179be", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", + "outputs": 1, + "x": 560, + "y": 580, + "wires": [ + [ + "ed35109311335099" + ] + ] + }, + { + "id": "ed35109311335099", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "2f4c0f98.dee2" + ], + "x": 655, + "y": 580, + "wires": [] + }, + { + "id": "1493398979a63775", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Combine", + "x": 420, + "y": 580, + "wires": [ + [ + "da325be8e74179be" + ] + ] + }, + { + "id": "ada1b6f7cccc9344", + "type": "link out", + "z": "80a3942785a26c29", + "name": "combine", + "mode": "link", + "links": [ + "6dd356510c446cf4" + ], + "x": 835, + "y": 180, + "wires": [] + }, + { + "id": "6dd356510c446cf4", + "type": "link in", + "z": "80a3942785a26c29", + "name": "combine", + "links": [ + "ada1b6f7cccc9344" + ], + "x": 175, + "y": 580, + "wires": [ + [ + "189c1eed09624a7b" + ] + ] + }, + { + "id": "b42e061fb1f1f3d7", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "397ab7f44b893c89", + "3876d5cbd248592b" + ], + "x": 435, + "y": 140, + "wires": [] + }, + { + "id": "b99505440832439f", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "diskspace", + "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", + "outputs": 1, + "x": 800, + "y": 100, + "wires": [ + [ + "92047434f8e9f927" + ] + ] + }, + { + "id": "92047434f8e9f927", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 950, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "f3662f8c7d3d7a2d", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "minute", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 650, + "y": 100, + "wires": [ + [ + "b99505440832439f" + ] + ] + }, + { + "id": "51579603bce21e98", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "read", + "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", + "outputs": 1, + "x": 130, + "y": 60, + "wires": [ + [ + "952ce286.4ffd4" + ] + ] + }, + { + "id": "9a5baae623355f9d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "preview", + "order": 6, + "width": 6, + "height": 6, + "format": "
\n\n\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1020, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "85839a17fb7b58b9", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "preview", + "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", + "outputs": 1, + "x": 880, + "y": 220, + "wires": [ + [ + "9a5baae623355f9d" + ] + ] + }, + { + "id": "01e4783e148c6698", + "type": "ui_table", + "z": "80a3942785a26c29", + "group": "b5fdd57b.15eda8", + "name": "", + "order": 1, + "width": 13, + "height": 7, + "columns": [ + { + "field": "Date", + "title": "Date", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Name", + "title": "Name", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Photos", + "title": "Photos", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Duration", + "title": "ΔT", + "width": "60", + "align": "left", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Size", + "title": "Size", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Status", + "title": "Status", + "width": "140", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + } + ], + "outputs": 1, + "cts": true, + "x": 610, + "y": 180, + "wires": [ + [ + "4082b136.dae18", + "50710948.71c308", + "834046a4.647938", + "0c387c0291d6c131" + ] + ] + }, + { + "id": "cb3437ec113e1b6f", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "SSH", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 3, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 390, + "y": 360, + "wires": [ + [ + "c24f61b87e3226dd" + ] + ] + }, + { + "id": "60fd0adce1cfeb82", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Samba", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "test2", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 400, + "wires": [ + [ + "441d3ef525e901da" + ] + ] + }, + { + "id": "c24f61b87e3226dd", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "ssh", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", + "outputs": 1, + "x": 530, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "c013e836e759a085", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "4390b2ebcbbe104c", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "label": "Terms Of Use", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 120, + "y": 320, + "wires": [ + [ + "b78346ca3ce70c68" + ] + ] + }, + { + "id": "f0d8dbcca76a1926", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "Agree", + "cancel": "Disagree", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 410, + "y": 320, + "wires": [ + [ + "e95b86cbac1b03b9" + ] + ] + }, + { + "id": "34374044c0030625", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "General", + "group": "4390b2ebcbbe104c", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

General Settings

Terms Of Use

In order to use the OpenScanCloud, please read the terms of use as files will be transmitted from your device to the OpenScan Servers.

SSH

SSH can be used to access the Raspberry Pi and modify core files of the operating system. Please deactivate, if you do not want to use this feature.

If you want to use it, the default user is pi, password: raspberry. Please change the password immediately. 

Samba

Samba s a network local file sharing server, which allows accessing the Raspberry Pi's file system through the explorer (and other programs like FileZilla). You can use it to transfer custom photo sets to the device in order to use the OpenScanCloud. Therefore, you need to transfer the zip file containing your photos to the following folder /OpenScan/scans/

You can access the Raspberry Pis file system by inserting the following line into your Windows explorer: 

\\\\OpenScan/PiShare/OpenScan/scans/

username: pi, password: raspberry

Please deactivate the local file sharing if you do not intend to use it

Advanced Settings

Enable a ton of additional settings, which should be changed only if you know what you are doing ;)

Model

Device model you are using: OpenScan Mini or OpenScan Classic. Setting the device affects the settings of the motor (gear ratio, acceleration, speed). You can change those values manually in the advanced settings.

Camera

A wide range of camera modules is supported (Pi camera v1.3, v2.1, HQ, Arducam IMX519, IMX290, IMX378, OV9281). If you encounter any issues with those models, please check the orientation of the camera ribbon cable and its connectors.

DSLR (gphoto) - connect a wide range of DSLR cameras to the device through USB. See GPhoto for a full list of supported devices.

External camera - triggering any camera through an isolated GPIO signal on the front side of the pi shield.

Shutdown/Reboot

Always use the shutdown button before you power off your Raspberry Pi.

Restore Default Settings

In case you want to restore the default settings

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "b2b6bf23c9989133", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Pinout", + "group": "70d0be671bf03ca7", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Pinout

ONLY CHANGE THE PINOUT IF YOU ARE ABSOLUTELY SURE! CHANGES CAN DAMAGE THE RASPBERRY PI AND ANY PERIPHERALS!


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "441d3ef525e901da", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "smb", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", + "outputs": 1, + "x": 530, + "y": 400, + "wires": [ + [] + ] + }, + { + "id": "3256bab150113a48", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Motor", + "group": "7a3279eea439bcdd", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Motor Settings

Turntable Mode

Activate turntable mode in order to deactivate the rotor. The routine will only move the turntable and take a given number of photos.

Rotor - Start Angle, Min and Max Angle

Since this version of OpenScan does not have an endstop (yet), it is necessary to tell the device its position when the routine is being started. 0° corresponds to the horizontal (natural) orientation.

After that, the device will equally space the image positions between angle min and angle max.

Rotor/Turntable

Steps per rotation -  defines the number of steps it takes to move the axis 360°. It is defined by A*B*C, where A is the number of steps for one revolution of the given stepper motor (normally 200), B is the microstepping used (normally 16), and C the gear ratio (1 for the turntable and 15 or 5,33 for the OpenScan Mini and Classic respectively)

Delay - time in microseconds between each step of the motor. Lower this value if the movement is too fast

Acceleration - a factor defining how fast the delay time between each step is being changed during acceleration and deceleration phases. Lower this value in order to make the movement smoother.

Acceleration ramp - the number of steps allowed for the acceleration processes. Increase this value, if you want smoother movement.

Manual Angle - Defines the degree value for the manual movement through the arrow buttons in the scan menu

Direction - If needed, reverse the movement (in case the arrow buttons and movement do not correspond). Alternatively, you can flip the motor cable 180° (BUT MAKE SURE TO POWER OFF THE DEVICE!)


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 140, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "7a186669a17daa71", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "camera", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Camera Settings

Jpeg quality

Value in percent, which usually does not need to be changed.

Downscale Preview

The preview image has to be scaled down depending on your network speed. If you want to have a higher quality preview image, you can increase this value, which defines the maximal width/height value. If the value is too high, the preview window might not update

Image Rotation

Change the image rotation, if needed.

Timeout

Defines the time in seconds, when the libcamera command (used for the camera modules) will timeout. Increase this value, if the camera does not get triggered in each position.

Delay Before/After

A fixed delay in seconds before and/or after a photo is taken. Increase this value when the photos have visual motion blur.

AWBG, Gain, Contrast, Saturation

Under most circumstances, you do not need to touch these values.

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 420, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "edac7dd292e7e486", + "type": "comment", + "z": "e43a27722b508115", + "name": "General Settings", + "info": "", + "x": 120, + "y": 280, + "wires": [] + }, + { + "id": "161b52034e578ee2", + "type": "comment", + "z": "e43a27722b508115", + "name": "Network", + "info": "", + "x": 100, + "y": 720, + "wires": [] + }, + { + "id": "f6d6cc35679ede63", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "more sets", + "label": "Advanced Settings", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 480, + "wires": [ + [ + "f06a7bcad524e9f9" + ] + ] + }, + { + "id": "29745a36fc157f3f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "more sets", + "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", + "outputs": 2, + "x": 820, + "y": 480, + "wires": [ + [ + "8750ad979e9ea246" + ], + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "bf23328f9fb11b22", + "type": "ui_ui_control", + "z": "e43a27722b508115", + "name": "change visibility", + "events": "all", + "x": 600, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "b37be1d222bc70c9", + "type": "inject", + "z": "e43a27722b508115", + "name": "1s_repeater", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "1", + "crontab": "", + "once": true, + "onceDelay": "2", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 150, + "y": 60, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "89eedf29b404f750", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, + "wires": [ + [ + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" + ] + ] + }, + { + "id": "2050de5d9e02f69f", + "type": "comment", + "z": "e43a27722b508115", + "name": "Info Texts", + "info": "", + "x": 100, + "y": 140, + "wires": [] + }, + { + "id": "ded3086945a6d4b5", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "check ip address", + "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", + "outputs": 1, + "x": 250, + "y": 940, + "wires": [ + [ + "3cfe464506f46ecd" + ] + ] + }, + { + "id": "3cfe464506f46ecd", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Your local IP:", + "format": "{{msg.ip}}", + "layout": "row-spread", + "className": "", + "x": 430, + "y": 940, + "wires": [] + }, + { + "id": "bd206ad109831e6a", + "type": "comment", + "z": "e43a27722b508115", + "name": "OpenScanCloud", + "info": "", + "x": 120, + "y": 1260, + "wires": [] + }, + { + "id": "b70a9a665c1e4d36", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Cloud-settings", + "group": "12b719cba49817c9", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

OpenScanCloud

OpenScanCloud is a free/donation-based cloud processing service, which will convert your photos into 3d models using latest photogrammetry technology. Feel free to support the project with a small donation at BuyMeACoffee.

The only requirement to use this service is a one-time, free-of-charge registration (which is solely an anti-spam measure). By filling out the registration form, you will receive an individual access token.

Register

In order to use the OpenScanCloud, you will have to enter your name and email. It might take 1-3 days to create the access token, which will be sent to your mail address. Please check your spam folder.

Enter Token

Please enter your individual token here in order to activate the cloud functionality. The token will be verified immediately. In case of any problems, please contact cloud@openscan.eu

Token

A shorted version of your token will be displayed here. Please include a copy of this shorted token in any support requests cloud@openscan.eu

Credit (GB)

Each token comes with a given amount of 'credit' which is another measure against spam. The given number in Gigabyte indicates the amount of data, that you can process on the servers. 

IMPORTANT: The credit can be increased at any time by sending a (nice) mail to cloud@openscan.eu

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 260, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "c9f0566601a3e130", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Number of Photos:", + "format": "{{msg.limit_photos}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 1400, + "wires": [] + }, + { + "id": "9bd86d27ea499a2a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Filesize (GB):", + "format": "{{msg.limit_filesize}}", + "layout": "row-spread", + "className": "", + "x": 390, + "y": 1440, + "wires": [] + }, + { + "id": "2c37f7030810d234", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Credit (GB):", + "format": "{{msg.credit}}", + "layout": "row-spread", + "className": "", + "x": 370, + "y": 1480, + "wires": [] + }, + { + "id": "f40286c18afd4501", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "save", + "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", + "outputs": 2, + "x": 750, + "y": 1340, + "wires": [ + [ + "455a5266017ea121", + "50f73cee213ec05c" + ], + [ + "264eece408043021" + ] + ] + }, + { + "id": "455a5266017ea121", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 890, + "y": 1300, + "wires": [ + [] + ] + }, + { + "id": "c368df68593bc2bf", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Token", + "tooltip": "", + "group": "12b719cba49817c9", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 350, + "y": 1360, + "wires": [ + [ + "18fd1afa768187b3" + ] + ] + }, + { + "id": "18fd1afa768187b3", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "Save?", + "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", + "outputs": 2, + "x": 470, + "y": 1360, + "wires": [ + [ + "418aea2ec65573a0" + ], + [ + "9792c89c5f4429f9" + ] + ] + }, + { + "id": "f90a98899b7a71d0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "text", + "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", + "outputs": 1, + "x": 230, + "y": 1360, + "wires": [ + [ + "c368df68593bc2bf" + ] + ] + }, + { + "id": "b4c843620c251c43", + "type": "link in", + "z": "e43a27722b508115", + "name": "token", + "links": [ + "960912e90ba5b5bc", + "50f73cee213ec05c", + "9792c89c5f4429f9", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1360, + "wires": [ + [ + "f90a98899b7a71d0" + ] + ] + }, + { + "id": "418aea2ec65573a0", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 1340, + "wires": [ + [ + "f40286c18afd4501" + ] + ] + }, + { + "id": "9792c89c5f4429f9", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "b4c843620c251c43" + ], + "x": 555, + "y": 1380, + "wires": [] + }, + { + "id": "264eece408043021", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "5d267acc10020091", + "3876d5cbd248592b" + ], + "x": 835, + "y": 1380, + "wires": [] + }, + { + "id": "3876d5cbd248592b", + "type": "link in", + "z": "e43a27722b508115", + "name": "OSCparameters", + "links": [ + "960912e90ba5b5bc", + "264eece408043021", + "b42e061fb1f1f3d7", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1400, + "wires": [ + [ + "5daca3ec47f8e7fc" + ] + ] + }, + { + "id": "50f73cee213ec05c", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "b4c843620c251c43", + "5d267acc10020091" + ], + "x": 835, + "y": 1340, + "wires": [] + }, + { + "id": "95578e54a9b61cba", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 250, + "y": 1540, + "wires": [ + [ + "d7a5693da7855da8" + ] + ] + }, + { + "id": "d7a5693da7855da8", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", + "outputs": 2, + "x": 390, + "y": 1540, + "wires": [ + [ + "2b02b97dd1614e52" + ], + [ + "183a629accb417b1" + ] + ] + }, + { + "id": "183a629accb417b1", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1580, + "wires": [ + [] + ] + }, + { + "id": "2b02b97dd1614e52", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1540, + "wires": [ + [ + "3e4c15d7b538f816" + ] + ] + }, + { + "id": "3bf622f344172721", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "SUBMIT", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 810, + "y": 1540, + "wires": [ + [ + "e431cb2b8d217cee" + ] + ] + }, + { + "id": "e431cb2b8d217cee", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", + "outputs": 1, + "x": 950, + "y": 1540, + "wires": [ + [ + "106874534890f229" + ] + ] + }, + { + "id": "a38d7fde5c73210f", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Register", + "group": "12b719cba49817c9", + "order": 6, + "width": 2, + "height": 1, + "passthru": false, + "label": "Register", + "tooltip": "testtesttest", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "Please enter your email address:", + "payloadType": "str", + "topic": "Requesting an OpenScanCloud Token", + "topicType": "str", + "x": 100, + "y": 1540, + "wires": [ + [ + "95578e54a9b61cba" + ] + ] + }, + { + "id": "106874534890f229", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 1090, + "y": 1540, + "wires": [ + [] + ] + }, + { + "id": "5daca3ec47f8e7fc", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", + "outputs": 1, + "x": 230, + "y": 1400, + "wires": [ + [ + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" + ] + ] + }, + { + "id": "f34de19d4cf810a9", + "type": "comment", + "z": "e43a27722b508115", + "name": "Motor", + "info": "", + "x": 90, + "y": 1740, + "wires": [] + }, + { + "id": "26c2b58e21f97475", + "type": "comment", + "z": "e43a27722b508115", + "name": "Camera", + "info": "", + "x": 90, + "y": 2500, + "wires": [] + }, + { + "id": "a8ec972bad47a9a8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Pinout", + "info": "", + "x": 90, + "y": 2960, + "wires": [] + }, + { + "id": "b03e8b51187e88eb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "Rotor_delay (ms)", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 16, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 450, + "y": 2100, + "wires": [ + [ + "11fd3363416433f9" + ] + ] + }, + { + "id": "6aae9d4fddf08cc0", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt delay", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 30, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 420, + "y": 2340, + "wires": [ + [ + "e50492d1e18f43c6" + ] + ] + }, + { + "id": "543e1690693acbeb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 18, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 420, + "y": 2140, + "wires": [ + [ + "e8b24efb0f30288e" + ] + ] + }, + { + "id": "9a56c087d941f1da", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 20, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "100", + "max": "5000", + "step": "100", + "className": "", + "x": 440, + "y": 2180, + "wires": [ + [ + "29f576be9e292232" + ] + ] + }, + { + "id": "dfdebe10dbf0e198", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotor_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 14, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 460, + "y": 2060, + "wires": [ + [ + "78e256083f59f66f" + ] + ] + }, + { + "id": "af8dfe78cbd0c301", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, + "width": 3, + "height": 1, + "name": "rotor Accramp", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2140, + "wires": [] + }, + { + "id": "ee4b8908a5b83880", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, + "width": 3, + "height": 1, + "name": "rotor_Steps per Rotation", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 810, + "y": 2180, + "wires": [] + }, + { + "id": "c4deaa38c1b0adbf", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, + "width": 3, + "height": 1, + "name": "rotor Acc", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2100, + "wires": [] + }, + { + "id": "baec873a95fff48a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, + "width": 3, + "height": 1, + "name": "rotor_delay", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 770, + "y": 2060, + "wires": [] + }, + { + "id": "355e89ab4e5484e4", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 26, + "width": 6, + "height": 1, + "name": "tt", + "label": "TURNTABLE", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 2300, + "wires": [] + }, + { + "id": "10687d331a732790", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 32, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 410, + "y": 2380, + "wires": [ + [ + "af88b9da72917d62" + ] + ] + }, + { + "id": "721b9680a3fa460e", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 34, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "500", + "step": "1", + "className": "", + "x": 430, + "y": 2420, + "wires": [ + [ + "b1b4678827d3a6dd" + ] + ] + }, + { + "id": "c6642c7470d3820c", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "tt_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 28, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 450, + "y": 2300, + "wires": [ + [ + "eef89545ec0f6aa8" + ] + ] + }, + { + "id": "18e5918748660109", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 33, + "width": 3, + "height": 1, + "name": "ttAccramp", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2420, + "wires": [] + }, + { + "id": "8e805244dc1899e8", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 27, + "width": 3, + "height": 1, + "name": "tt_steps per Rotation", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 800, + "y": 2300, + "wires": [] + }, + { + "id": "a09e5fbea861bfb1", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 31, + "width": 3, + "height": 1, + "name": "tt Acc", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 750, + "y": 2380, + "wires": [] + }, + { + "id": "7b06448b3b222011", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 29, + "width": 3, + "height": 1, + "name": "tt_delay", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2340, + "wires": [] + }, + { + "id": "0dfc86d90258f9bb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 22, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 430, + "y": 2220, + "wires": [ + [ + "c4b5a38c5c1df3d2" + ] + ] + }, + { + "id": "9319d7d4f34c6d22", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, + "width": 3, + "height": 1, + "name": "rotor_angle", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 770, + "y": 2220, + "wires": [] + }, + { + "id": "1610895f430b9aca", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 36, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 420, + "y": 2460, + "wires": [ + [ + "0f3367983bb8e159" + ] + ] + }, + { + "id": "96a9febc0928b6f0", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 35, + "width": 3, + "height": 1, + "name": "tt_angle", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2460, + "wires": [] + }, + { + "id": "e2c5ea8c16a5ea32", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, + "width": 6, + "height": 1, + "name": "rotor", + "label": "ROTOR", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 1820, + "wires": [] + }, + { + "id": "277037c4716d85bf", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 38, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 410, + "y": 2500, + "wires": [ + [ + "c9d2e31514def4fc" + ] + ] + }, + { + "id": "1361134e9847f003", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 24, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 420, + "y": 2260, + "wires": [ + [ + "523717b0f218a5fd" + ] + ] + }, + { + "id": "6b0d58943ecb8bb2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 37, + "width": 3, + "height": 1, + "name": "tt_dir", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2500, + "wires": [] + }, + { + "id": "08f93dd2aeedb391", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, + "width": 3, + "height": 1, + "name": "rotor_dir", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2260, + "wires": [] + }, + { + "id": "46b91bef44714366", + "type": "link in", + "z": "e43a27722b508115", + "name": "advanced settings", + "links": [ + "8750ad979e9ea246" + ], + "x": 95, + "y": 100, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "8750ad979e9ea246", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "46b91bef44714366" + ], + "x": 955, + "y": 480, + "wires": [] + }, + { + "id": "2522f888dc58972f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_before", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 430, + "y": 2600, + "wires": [ + [ + "5c752757090c49d2" + ] + ] + }, + { + "id": "30e8df3d616512d8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_gain", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "10", + "step": "0.1", + "className": "", + "x": 400, + "y": 2640, + "wires": [ + [ + "a1769f0277834f6d" + ] + ] + }, + { + "id": "d855d926df89d65b", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_contrast", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2760, + "wires": [ + [ + "1a8b0ba21b4f3005", + "654bc70a18820828" + ] + ] + }, + { + "id": "7617517dc8ba2859", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_saturation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2800, + "wires": [ + [ + "dc8fc962ff7d594b", + "e64feb03a791ca33" + ] + ] + }, + { + "id": "cbaa23c34e10fae1", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_jpeg_q", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 3, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "100", + "step": "1", + "className": "", + "x": 410, + "y": 2840, + "wires": [ + [ + "00e7836ccb3c4d0c" + ] + ] + }, + { + "id": "bbe443b039a14e21", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, + "width": 3, + "height": 1, + "name": "delay_before", + "label": "Delay before", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2600, + "wires": [] + }, + { + "id": "d320ed3d701e6cc2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, + "width": 3, + "height": 1, + "name": "gain", + "label": "Gain", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2640, + "wires": [] + }, + { + "id": "f5834dd4646c8af9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, + "width": 3, + "height": 1, + "name": "contrast", + "label": "Contrast", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2760, + "wires": [] + }, + { + "id": "ae9a4e19469813ef", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, + "width": 3, + "height": 1, + "name": "saturation", + "label": "Saturation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2800, + "wires": [] + }, + { + "id": "bd629d0d31233c8b", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 2, + "width": 3, + "height": 1, + "name": "jpegQ", + "label": "Jpeg Quality", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2840, + "wires": [] + }, + { + "id": "e89f61dbe6a6cffe", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ext", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 3, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3000, + "wires": [ + [ + "885bc559fafec5f2" + ] + ] + }, + { + "id": "ece38cb172a12d75", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 2, + "width": 4, + "height": 1, + "name": "ext", + "label": "External Camera", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3000, + "wires": [] + }, + { + "id": "70014da0b6ab6698", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3040, + "wires": [ + [ + "f70321c96bf81360" + ] + ] + }, + { + "id": "29634ea5f6d666df", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 4, + "width": 4, + "height": 1, + "name": "light1", + "label": "Light 1", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3040, + "wires": [] + }, + { + "id": "2544963852c6881a", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 7, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3080, + "wires": [ + [ + "95e1603bbd06a69d" + ] + ] + }, + { + "id": "27903533cd85a59e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 6, + "width": 4, + "height": 1, + "name": "light2", + "label": "Light 2", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3080, + "wires": [] + }, + { + "id": "a1394401246eb735", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotordir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 9, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3120, + "wires": [ + [ + "a8f92ea6bf394640" + ] + ] + }, + { + "id": "bc0aa4bacdfa94ea", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 8, + "width": 4, + "height": 1, + "name": "rotordir", + "label": "Rotor direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3120, + "wires": [] + }, + { + "id": "f15ca4518b5f223e", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotorstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 11, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3160, + "wires": [ + [ + "06397bb46b3bb541" + ] + ] + }, + { + "id": "0d2924b160e7e383", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 10, + "width": 4, + "height": 1, + "name": "rotorstep", + "label": "Rotor step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3160, + "wires": [] + }, + { + "id": "49900bb9047dd965", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotoren", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 13, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3200, + "wires": [ + [ + "687dcdc1ede11700" + ] + ] + }, + { + "id": "a4d743ca73ee1622", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 12, + "width": 4, + "height": 1, + "name": "rotoren", + "label": "Rotor enable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3200, + "wires": [] + }, + { + "id": "5a90224dc998b417", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttdir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 15, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3240, + "wires": [ + [ + "e220740c0d38ccb0" + ] + ] + }, + { + "id": "67dc1b544c4ddf9f", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 14, + "width": 4, + "height": 1, + "name": "ttdir", + "label": "Turntable direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3240, + "wires": [] + }, + { + "id": "d2364ab09627fe94", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 17, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3280, + "wires": [ + [ + "79d7e5a705ab813a" + ] + ] + }, + { + "id": "145b67ac40721ba6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 16, + "width": 4, + "height": 1, + "name": "ttstep", + "label": "Turntable step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3280, + "wires": [] + }, + { + "id": "eef25405472acfee", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 19, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3320, + "wires": [ + [ + "12d20f2274bcc511" + ] + ] + }, + { + "id": "35eb252a41413531", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 18, + "width": 4, + "height": 1, + "name": "endstop1", + "label": "Endstop Rotor", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3320, + "wires": [] + }, + { + "id": "5fcef1cb2e9e4788", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "confirm", + "x": 680, + "y": 480, + "wires": [ + [ + "29745a36fc157f3f" + ] + ] + }, + { + "id": "f06a7bcad524e9f9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", + "outputs": 1, + "x": 530, + "y": 480, + "wires": [ + [ + "5fcef1cb2e9e4788" + ] + ] + }, + { + "id": "f455fb39039617ae", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_rotation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "270", + "step": "90", + "className": "", + "x": 410, + "y": 2880, + "wires": [ + [ + "3019576de193d9d6" + ] + ] + }, + { + "id": "fdfbc900fe424eb9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, + "width": 3, + "height": 1, + "name": "cam_rot", + "label": "Image Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2880, + "wires": [] + }, + { + "id": "c3699d6b9664ccca", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2060, + "wires": [ + [ + "dfdebe10dbf0e198" + ] + ] + }, + { + "id": "78e256083f59f66f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2060, + "wires": [ + [] + ] + }, + { + "id": "0f9141b401322374", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2180, + "wires": [ + [ + "9a56c087d941f1da" + ] + ] + }, + { + "id": "29f576be9e292232", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2180, + "wires": [ + [] + ] + }, + { + "id": "23e3099b34c4e475", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2220, + "wires": [ + [ + "0dfc86d90258f9bb" + ] + ] + }, + { + "id": "c4b5a38c5c1df3d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2220, + "wires": [ + [] + ] + }, + { + "id": "79a14162ac805fac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2260, + "wires": [ + [ + "1361134e9847f003" + ] + ] + }, + { + "id": "523717b0f218a5fd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2260, + "wires": [ + [] + ] + }, + { + "id": "f5cf780f3fa8997e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2100, + "wires": [ + [ + "b03e8b51187e88eb" + ] + ] + }, + { + "id": "11fd3363416433f9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2100, + "wires": [ + [] + ] + }, + { + "id": "02060b3f3b294563", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2140, + "wires": [ + [ + "543e1690693acbeb" + ] + ] + }, + { + "id": "e8b24efb0f30288e", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2140, + "wires": [ + [] + ] + }, + { + "id": "de1ad8b27b72a5ac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nsteps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", + "outputs": 1, + "noerr": 4, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2300, + "wires": [ + [ + "c6642c7470d3820c" + ] + ] + }, + { + "id": "ed4d587cb4feb064", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2420, + "wires": [ + [ + "721b9680a3fa460e" + ] + ] + }, + { + "id": "5b02160c33605ae7", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2460, + "wires": [ + [ + "1610895f430b9aca" + ] + ] + }, + { + "id": "304c135ec09801e3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2500, + "wires": [ + [ + "277037c4716d85bf" + ] + ] + }, + { + "id": "a91dcbe0f9a2416a", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2340, + "wires": [ + [ + "6aae9d4fddf08cc0" + ] + ] + }, + { + "id": "6b2eb1cb95e573f9", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2380, + "wires": [ + [ + "10687d331a732790" + ] + ] + }, + { + "id": "eef89545ec0f6aa8", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2300, + "wires": [ + [] + ] + }, + { + "id": "b1b4678827d3a6dd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2420, + "wires": [ + [] + ] + }, + { + "id": "0f3367983bb8e159", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2460, + "wires": [ + [] + ] + }, + { + "id": "c9d2e31514def4fc", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2500, + "wires": [ + [] + ] + }, + { + "id": "e50492d1e18f43c6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2340, + "wires": [ + [] + ] + }, + { + "id": "af88b9da72917d62", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2380, + "wires": [ + [] + ] + }, + { + "id": "43fe948b3e7234e2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2600, + "wires": [ + [ + "2522f888dc58972f" + ] + ] + }, + { + "id": "5c752757090c49d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2600, + "wires": [ + [] + ] + }, + { + "id": "435681b3f7625a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2640, + "wires": [ + [ + "30e8df3d616512d8" + ] + ] + }, + { + "id": "a1769f0277834f6d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2640, + "wires": [ + [] + ] + }, + { + "id": "1de07c7d285cbaf3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2760, + "wires": [ + [ + "d855d926df89d65b" + ] + ] + }, + { + "id": "1a8b0ba21b4f3005", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2760, + "wires": [ + [] + ] + }, + { + "id": "ebc9e283468eda31", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2800, + "wires": [ + [ + "7617517dc8ba2859" + ] + ] + }, + { + "id": "dc8fc962ff7d594b", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2800, + "wires": [ + [] + ] + }, + { + "id": "60d641613527c736", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2840, + "wires": [ + [ + "cbaa23c34e10fae1" + ] + ] + }, + { + "id": "00e7836ccb3c4d0c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2840, + "wires": [ + [] + ] + }, + { + "id": "7f24c0c34a88ba04", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2880, + "wires": [ + [ + "f455fb39039617ae" + ] + ] + }, + { + "id": "3019576de193d9d6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2880, + "wires": [ + [] + ] + }, + { + "id": "77bb7dc529d63a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3000, + "wires": [ + [ + "e89f61dbe6a6cffe" + ] + ] + }, + { + "id": "885bc559fafec5f2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3000, + "wires": [ + [] + ] + }, + { + "id": "cc6dabe017a9c8a8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3320, + "wires": [ + [ + "eef25405472acfee" + ] + ] + }, + { + "id": "12d20f2274bcc511", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3320, + "wires": [ + [] + ] + }, + { + "id": "dcb9fed8122759fd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3040, + "wires": [ + [ + "70014da0b6ab6698" + ] + ] + }, + { + "id": "f70321c96bf81360", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3040, + "wires": [ + [] + ] + }, + { + "id": "013d2057c2347a62", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3080, + "wires": [ + [ + "2544963852c6881a" + ] + ] + }, + { + "id": "95e1603bbd06a69d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3080, + "wires": [ + [] + ] + }, + { + "id": "f88bbf11d5aa9a14", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3120, + "wires": [ + [ + "a1394401246eb735" + ] + ] + }, + { + "id": "a8f92ea6bf394640", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3120, + "wires": [ + [] + ] + }, + { + "id": "301af70731e096e5", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3160, + "wires": [ + [ + "f15ca4518b5f223e" + ] + ] + }, + { + "id": "06397bb46b3bb541", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3160, + "wires": [ + [] + ] + }, + { + "id": "0456a9ec4c236c9e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3200, + "wires": [ + [ + "49900bb9047dd965" + ] + ] + }, + { + "id": "687dcdc1ede11700", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3200, + "wires": [ + [] + ] + }, + { + "id": "09d37ba08ec0f163", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3240, + "wires": [ + [ + "5a90224dc998b417" + ] + ] + }, + { + "id": "37d954a4cf7e87ea", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3280, + "wires": [ + [ + "d2364ab09627fe94" + ] + ] + }, + { + "id": "e220740c0d38ccb0", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3240, + "wires": [ + [] + ] + }, + { + "id": "79d7e5a705ab813a", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3280, + "wires": [ + [] + ] + }, + { + "id": "22ef66b0e2058be2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 360, + "wires": [ + [ + "cb3437ec113e1b6f" + ] + ] + }, + { + "id": "9ce01c8ba97932c1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 400, + "wires": [ + [ + "60fd0adce1cfeb82" + ] + ] + }, + { + "id": "81356177176eebcf", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 7, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 480, + "wires": [ + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "b78346ca3ce70c68", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 320, + "wires": [ + [ + "f0d8dbcca76a1926" + ] + ] + }, + { + "id": "e95b86cbac1b03b9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "3e4c15d7b538f816", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 670, + "y": 1540, + "wires": [ + [ + "3bf622f344172721" + ] + ] + }, + { + "id": "0f0871baf322b6d0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1820, + "wires": [ + [ + "6ebd15c61a5ca891" + ] + ] + }, + { + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1820, + "wires": [ + [] + ] + }, + { + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, + "wires": [ + [ + "acd10a4c99ee8063" + ] + ] + }, + { + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, + "wires": [ + [ + "031d7697768d0e77" + ] + ] + }, + { + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, + "wires": [ + [ + "be1954dd71d2c94c" + ] + ] + }, + { + "id": "edb1c8fae8b65c82", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1860, + "wires": [ + [ + "3ad0f0f206e4a873" + ] + ] + }, + { + "id": "031d7697768d0e77", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1860, + "wires": [ + [] + ] + }, + { + "id": "462a8f3ca75fc3c8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1900, + "wires": [ + [ + "3b6d759ed5be647f" + ] + ] + }, + { + "id": "be1954dd71d2c94c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1900, + "wires": [ + [] + ] + }, + { + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, + "wires": [ + [ + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88", + "53681e53353db898" + ] + ] + }, + { + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, + "y": 940, + "wires": [ + [ + "ded3086945a6d4b5", + "6ea3cdab41f20f92" + ] + ] + }, + { + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, + "wires": [ + [ + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd" + ] + ] + }, + { + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2540, + "wires": [ + [ + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" + ] + ] + }, + { + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3000, + "wires": [ + [ + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8" + ] + ] + }, + { + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 620, + "wires": [ + [ + "53e6681d7254d484" + ] + ] + }, + { + "id": "53e6681d7254d484", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 270, + "y": 620, + "wires": [ + [ + "c11e79cfa7bc10b7" + ] + ] + }, + { + "id": "c11e79cfa7bc10b7", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 620, + "wires": [ + [ + "307782d10c1acdaf" + ] + ] + }, + { + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 620, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "cca3300a8f0daf4d", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 750, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "654bc70a18820828", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_contrast?contrast=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2720, + "wires": [ + [] + ] + }, + { + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_saturation?saturation=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2680, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2560, + "wires": [ + [ + "e612073aded01a8f" + ] + ] + }, + { + "id": "0d92559980944ae3", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, + "width": 3, + "height": 1, + "name": "delay_after", + "label": "Delay after", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2560, + "wires": [] + }, + { + "id": "6281b2e6e081104d", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2560, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2560, + "wires": [ + [] + ] + }, + { + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 560, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 560, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 210, + "y": 980, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 220, + "y": 1020, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 240, + "y": 1060, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] + }, + { + "id": "a7d233f984009e2e", + "type": "function", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 440, + "y": 980, + "wires": [ + [ + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" + ] + ] + }, + { + "id": "65518f3d4e3095e5", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 1", + "links": [ + "200d4b9951b6e066" + ], + "x": 85, + "y": 980, + "wires": [ + [ + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" + ] + ] + }, + { + "id": "9b851aa999e86fd7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", + "outputs": 1, + "x": 670, + "y": 980, + "wires": [ + [ + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" + ] + ] + }, + { + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 870, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, + "wires": [] + }, + { + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", + "links": [ + "592ec13d8f8923a9" + ], + "x": 815, + "y": 1020, + "wires": [] + }, + { + "id": "1eef47e0074545a9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, + "wires": [ + [ + "c994c779e4bad800", + "36890eb99a2ca1cf" + ], + [] + ] + }, + { + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, + "wires": [ + [ + "1eef47e0074545a9" + ] + ] + }, + { + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", + "name": "", + "x": 670, + "y": 1020, + "wires": [] + }, + { + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, + "wires": [] + }, + { + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, + "wires": [ + [ + "85ad07b8f973bbe2" + ] + ] + }, + { + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "endstop_angle", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2020, + "wires": [] + }, + { + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, + "wires": [ + [] + ] + }, + { + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, + "wires": [ + [ + "6b7245c3dcb694c8" + ] + ] + }, + { + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, + "wires": [ + [ + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" + ] + ] + }, + { + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, + "wires": [ + [ + "253feafa5a2f8b1d" + ] + ] + }, + { + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, + "wires": [ + [] + ] + }, + { + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_enable_endstop", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 450, + "y": 1980, + "wires": [ + [ + "69516440e3997111", + "f036424d79645761" + ] + ] + }, + { + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, + "wires": [ + [ + "eefed04c25e3e4d6" + ] + ] + }, + { + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, + "wires": [ + [ + "2aaf7c7f0f0c146f" + ] + ] + }, + { + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", + "outputs": 1, + "x": 660, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3560, + "wires": [ + [ + "d0a1a4947a1137ca" + ] + ] + }, + { + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 540, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] + }, + { + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, + "wires": [ + [] + ] + }, + { + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3640, + "wires": [ + [ + "b5aba11033c5f952" + ] + ] + }, + { + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, + { + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "e98c1b83744bb863", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Delete Aborted", + "tooltip": "Delete aborted photosets", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 420, + "y": 520, + "wires": [ + [ + "7438a5bf5fcddec4" + ] + ] + }, + { + "id": "7438a5bf5fcddec4", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "delete_aborted", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('delete_aborted'):\n save('delete_aborted', state)\n", + "outputs": 1, + "x": 600, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "53681e53353db898", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'delete_aborted'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 520, + "wires": [ + [ + "e98c1b83744bb863" + ] + ] + }, + { + "id": "48386fdb54980ec7", + "type": "comment", + "z": "e43a27722b508115", + "name": "Shield", + "info": "", + "x": 90, + "y": 3760, + "wires": [] + }, + { + "id": "fbc5fc2e65311f8b", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 3", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3840, + "wires": [ + [ + "5618e266f6966ae6" + ] + ] + }, + { + "id": "5618e266f6966ae6", + "type": "function", + "z": "e43a27722b508115", + "name": "loadl", + "func": "var file = 'shield_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 170, + "y": 3840, + "wires": [ + [ + "c97113d841391e40" + ] + ] + }, + { + "id": "c97113d841391e40", + "type": "ui_dropdown", + "z": "e43a27722b508115", + "name": "", + "label": "Shield Type", + "tooltip": "", + "place": "Select option", + "group": "0b244f698c7ac9a2", + "order": 0, + "width": 0, + "height": 0, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "Green", + "value": "green", + "type": "str" + }, + { + "label": "Black", + "value": "black", + "type": "str" + } + ], + "payload": "", + "topic": "payload", + "topicType": "msg", + "className": "", + "x": 310, + "y": 3840, + "wires": [ + [ + "2b639346c1b56578" + ] + ] + }, + { + "id": "2b639346c1b56578", + "type": "function", + "z": "e43a27722b508115", + "name": "function 2", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'shield_type';\nconst current_shield = fs.readFileSync(filepath + file, 'utf8');\n\nvar current_choice = msg.payload\n\nif (current_choice != current_shield) {\n \n switch (current_choice) {\n case \"green\":\n fs.writeFile(filepath + 'pin_external', String(10), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(17), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(9), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(11), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(14), err => {\n if (err) {\n return\n }\n });\n break;\n case \"black\":\n fs.writeFile(filepath + 'pin_external', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(24), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(22), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(17), err => {\n if (err) {\n return\n }\n });\n break;\n case \"custom\":\n break;\n }\n\n fs.writeFile(filepath + file, current_choice, err => {\n if (err) {\n return\n }\n });\n}\n\nmsg.status = 'The new ' + current_choice + ' shield has been configured'\nmsg.topic = msg.status\nmsg.payload = 'Do you want to reboot now to apply the changes?'\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 460, + "y": 3840, + "wires": [ + [ + "137f032887544d74" + ] + ] + }, + { + "id": "137f032887544d74", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": false, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Reboot", + "x": 600, + "y": 3840, + "wires": [ + [ + "d2db49796fe0da79", + "d0d6820224b0ab0f" + ] + ] + }, + { + "id": "d2db49796fe0da79", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "print(msg['payload'])\nreturn msg", + "outputs": 1, + "x": 790, + "y": 3840, + "wires": [ + [] + ] + }, + { + "id": "d0d6820224b0ab0f", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 6", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 780, + "y": 3720, + "wires": [] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'stable'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, + "wires": [ + [ + "e23c514008cad1a1" + ] + ] + }, + { + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] + }, + { + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, + "wires": [ + [ + "4ce127c61c3c5966", + "beacc3dc5398fa79" + ] + ] + }, + { + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", + "outputs": 1, + "x": 290, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "beacc3dc5398fa79", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "e23c514008cad1a1", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 480, + "y": 140, + "wires": [] + }, + { + "id": "b0629875a30ae1d7", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", + "outputs": 2, + "x": 390, + "y": 540, + "wires": [ + [ + "1bbe2d769f42c313" + ], + [ + "fefe45404bdb19c4" + ] + ] + }, + { + "id": "c7b6d05a62172432", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Status:", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 210, + "y": 400, + "wires": [] + }, + { + "id": "fefe45404bdb19c4", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "check files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "outputs": 1, + "x": 550, + "y": 560, + "wires": [ + [ + "1bbe2d769f42c313", + "ae92a328af306ebb" + ] + ] + }, + { + "id": "d0104e0163745993", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 115, + "y": 440, + "wires": [ + [ + "ec30638407332e43", + "38cbf7965d1c1834", + "49f1ecb29a3f84f4" + ] + ] + }, + { + "id": "ec30638407332e43", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadS", + "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 480, + "wires": [ + [ + "2852023f3aa8db10" + ] + ] + }, + { + "id": "2852023f3aa8db10", + "type": "ui_dropdown", + "z": "a5557543ccff5889", + "name": "", + "label": "", + "tooltip": "", + "place": "Select option", + "group": "ddbd496e.93a288", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "stable", + "value": "stable", + "type": "str" + }, + { + "label": "beta", + "value": "beta", + "type": "str" + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" + } + ], + "payload": "", + "topic": "topic", + "topicType": "msg", + "className": "", + "x": 340, + "y": 480, + "wires": [ + [ + "1e10b387ee30c486" + ] + ] + }, + { + "id": "1e10b387ee30c486", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "274129c51b0b87ef", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 4, + "width": 4, + "height": 1, + "name": "", + "label": "Updatetype: ", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 610, + "y": 480, + "wires": [] + }, + { + "id": "51cd8c8643e6b46a", + "type": "ui_switch", + "z": "a5557543ccff5889", + "name": "", + "label": "Auto-check update availability", + "tooltip": "", + "group": "ddbd496e.93a288", + "order": 6, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 410, + "y": 440, + "wires": [ + [ + "1ab4c6b4b232a022" + ] + ] + }, + { + "id": "38cbf7965d1c1834", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 440, + "wires": [ + [ + "51cd8c8643e6b46a" + ] + ] + }, + { + "id": "1ab4c6b4b232a022", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 610, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "ae92a328af306ebb", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "NO", + "cancel": "YES", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 710, + "y": 560, + "wires": [ + [ + "2de63e8e3ae5fb0c", + "929281fef53e09f8" + ] + ] + }, + { + "id": "cbd0afc4aa7b302a", + "type": "link in", + "z": "a5557543ccff5889", + "name": "update status", + "links": [ + "1bbe2d769f42c313", + "42061b28cff81f99" + ], + "x": 115, + "y": 400, + "wires": [ + [ + "c7b6d05a62172432", + "c94623ddd9d95f78" + ] + ] + }, + { + "id": "1bbe2d769f42c313", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 665, + "y": 520, + "wires": [] + }, + { + "id": "7cf60615d93e696b", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 7, + "width": 6, + "height": 1, + "passthru": false, + "label": "Check Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 180, + "y": 560, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "2de63e8e3ae5fb0c", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "download files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "outputs": 1, + "x": 880, + "y": 560, + "wires": [ + [ + "42061b28cff81f99", + "fe3a855fee9e28c6" + ] + ] + }, + { + "id": "929281fef53e09f8", + "type": "function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 850, + "y": 520, + "wires": [ + [ + "42061b28cff81f99" + ] + ] + }, + { + "id": "42061b28cff81f99", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 995, + "y": 520, + "wires": [] + }, + { + "id": "49f1ecb29a3f84f4", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 520, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "fe3a855fee9e28c6", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "9bb0adbd716ce347", + "01c882fcc51b349c" + ], + "x": 995, + "y": 560, + "wires": [] + }, + { + "id": "5e7d5e4335d37794", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 95, + "y": 700, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "2bb5fe78e09fec8a", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", + "outputs": 1, + "x": 210, + "y": 700, + "wires": [ + [ + "dbc77052ac950624", + "d97c3068ef5fef96", + "73a3b828f862312b", + "901e31453b2bdff8", + "f983854748ee4763", + "5347c7c517f5e8c7", + "3a5016f7003cd72c", + "6d720c4a4ecd9475", + "6438b7d060a70d81" + ] + ] + }, + { + "id": "d97c3068ef5fef96", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "OS:", + "format": "{{msg.os}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 740, + "wires": [] + }, + { + "id": "73a3b828f862312b", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 8, + "width": 0, + "height": 0, + "name": "", + "label": "Flask:", + "format": "{{msg.flask}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 780, + "wires": [] + }, + { + "id": "dbc77052ac950624", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Device:", + "format": "{{msg.device}}", + "layout": "row-spread", + "className": "", + "x": 500, + "y": 700, + "wires": [] + }, + { + "id": "3f42560297fe6978", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "name": "Download LOG", + "order": 9, + "width": 6, + "height": 1, + "format": "\n
Download error log\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 180, + "y": 1060, + "wires": [ + [] + ] + }, + { + "id": "c94623ddd9d95f78", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", + "outputs": 1, + "x": 210, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "39a502b38837273d", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "1e7457ea9c2c5e09" + ], + "x": 245, + "y": 600, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "901e31453b2bdff8", + "type": "delay", + "z": "a5557543ccff5889", + "name": "", + "pauseType": "delay", + "timeout": "10", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 220, + "y": 740, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "f983854748ee4763", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "", + "format": "{{msg.osdate}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 820, + "wires": [] + }, + { + "id": "5347c7c517f5e8c7", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "CPU temp:", + "format": "{{msg.temp}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 860, + "wires": [] + }, + { + "id": "3a5016f7003cd72c", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "CPU memory:", + "format": "{{msg.cpu}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 900, + "wires": [] + }, + { + "id": "6d720c4a4ecd9475", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 6, + "width": 0, + "height": 0, + "name": "", + "label": "Swap memory:", + "format": "{{msg.swap}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 940, + "wires": [] + }, + { + "id": "6438b7d060a70d81", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 7, + "width": 0, + "height": 0, + "name": "", + "label": "Diskspace:", + "format": "{{msg.diskspace}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 980, + "wires": [] + }, + { + "id": "8d012912f302be85", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 8, + "width": 6, + "height": 1, + "passthru": false, + "label": "Show Details/Changelog", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 210, + "y": 640, + "wires": [ + [ + "5242607a723cc628" + ] + ] + }, + { + "id": "5242607a723cc628", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "Changelog", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "outputs": 1, + "x": 430, + "y": 640, + "wires": [ + [ + "573722197b15bf84" + ] + ] + }, + { + "id": "573722197b15bf84", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 640, + "wires": [ + [] + ] + }, + { + "id": "9b3e6a06c82a0f52", + "type": "link in", + "z": "87715429b0b1c9a3", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 55, + "y": 120, + "wires": [ + [ + "f128ca405d1e1e4d", + "07d7ce3dab5f1c11" + ] + ] + }, + { + "id": "cd0dc08fcb5968c8", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Successful Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 450, + "y": 180, + "wires": [] + }, + { + "id": "f128ca405d1e1e4d", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics.csv|grep -vi false|tail -n +2|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Successful Scans", + "x": 210, + "y": 180, + "wires": [ + [ + "cd0dc08fcb5968c8" + ], + [], + [] + ] + }, + { + "id": "b91b4d65f2090793", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Aborted Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 440, + "y": 120, + "wires": [] + }, + { + "id": "07d7ce3dab5f1c11", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics.csv|grep -vi True|tail -n +2|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Aborted Scans", + "x": 200, + "y": 120, + "wires": [ + [ + "b91b4d65f2090793" + ], + [], + [] + ] + }, + { + "id": "5b3aa9a71591ba34", + "type": "comment", + "z": "87715429b0b1c9a3", + "name": "Statistics", + "info": "", + "x": 100, + "y": 40, + "wires": [] + } +] \ No newline at end of file diff --git a/update/2024-11S/meanwhile/routine.py b/update/2024-11S/meanwhile/routine.py new file mode 100644 index 0000000..4f7aeca --- /dev/null +++ b/update/2024-11S/meanwhile/routine.py @@ -0,0 +1,251 @@ +# The contents of this file are embedded in the OpenScan app (Node-RED) +from OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \ + load_bool, camera +from time import sleep, strftime, time +from subprocess import getoutput, run + +from zipfile import ZipFile, ZIP_DEFLATED +from os import system, uname +from os.path import isfile, getsize +import math +import threading +import numpy as np +import json + +if load_str("status_internal_cam") == "no camera found" or load_str("status_internal_cam")[:5] == "Featu": + return + +save('status_internal_cam', 'Routine-preparing') +camera('/v1/camera/picam2_switch_mode?mode=1') + +save('cam_sharparea', False) +save('cam_features', False) + +projectname = load_str("routine_projectname") +angle_max = load_int('rotor_anglemax') +angle_min = load_int('rotor_anglemin') +if load_bool('rotor_enable_endstop'): + angle_start = load_int('rotor_endstop_angle') + motorrun('rotor',angle_start/abs(angle_start) * 130, True, False) + +else: + angle_start = load_int('rotor_anglestart') + + +photocount = load_int('routine_photocount') + +focus_min = load_float('cam_focus_min') +focus_max = load_float('cam_focus_max') +stacksize = load_int('cam_stacksize') +group_stack_photos = load_bool('group_stack_photos') + +telegram_enable = load_bool('telegram_enable') +if telegram_enable: + telegram_api_token = load_str('telegram_api_token') + telegram_client_id = load_str('telegram_client_id') + +if focus_min == focus_max: + stacksize = 1 + +focuslist = [] +if stacksize == 1: + steps = 3 + int(abs(focus_max-focus_min)*0.8) +else: + steps = stacksize + +for i in range (steps): + focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1)) + +msg['focuslist'] = focuslist +msg['payload2'] = [] +counter = 0 + +basepath = '/home/pi/OpenScan/' +temppath = basepath + 'tmp2/preview.jpg' +zippath = basepath + 'tmp.zip' + +projectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname + +if isfile(zippath): + system('rm ' + zippath) +sleep(1) + +coordinates = create_coordinates(angle_min, angle_max, photocount) +coordinates = sort_spherical_coordinates_deg(coordinates) + +msg['payload'] = coordinates + +position_last = (angle_start, 0) + +zip = ZipFile(zippath, "a", ZIP_DEFLATED, allowZip64=True) + +hostname = str(uname()[1]) + +starttime = time() + +def get_eta(starttime, photocounter, count): + return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str( + int(photocount / counter * (time() - starttime))) + 's' + +def photo(counter2): + camera('/v1/camera/picam2_take_photo') + returning[0] = focus(returning[0]) + zip.write(temppath, projectname + '_' + str(counter) + ".jpg") + +def stack_photo(i): + + camera('/v1/camera/picam2_take_photo') + if group_stack_photos: + name = projectname + '_' + str(counter) + "/" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg' + else: + name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg' + zip.write(temppath, name) + +def stack_focus(i): + sleep(load_float('cam_shutter')/1000000*2) + if i < len(focuslist)-1: + camera('/v1/camera/picam2_focus?focus=' + str(focuslist[i+1])) + else: + camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0])) + sleep(1.7) + +def photo_stack(): + camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0])) + for i in range(len(focuslist)): + if load_str('status_internal_cam') == "Routine-stopping": + break + save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + "-F"+ str(i+1)) + + focus_thread = threading.Thread(target=stack_focus, args=(i,)) + photo_thread = threading.Thread(target=stack_photo, args=(i,)) + + focus_thread.start() + photo_thread.start() + + focus_thread.join() + photo_thread.join() + + + +def move_motor(): + rotor_angle = position[0] - position_last[0] + msg['payload2'].append(rotor_angle) + #if abs(rotor_angle) > 180: + # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle + tt_angle = position_last[1] - position[1] + if tt_angle > 180: + tt_angle -= 360 + elif tt_angle < -180: + tt_angle += 360 + + motorrun('tt',tt_angle) + motorrun('rotor',rotor_angle) + return + + # THE FOLLOWING DOES NOT WORK PROPERLY WITH THREADING ?! + + #tt_thread = threading.Thread(target=motorrun, args=('tt', tt_angle)) + #rotor_thread = threading.Thread(target=motorrun, args=('rotor', rotor_angle)) + #tt_thread.start() + #rotor_thread.start() + #tt_thread.join() + #rotor_thread.join() + + +counter2 = 0 + +def check_diskspace(): + diskspace_threshold = load_int('diskspace_threshold') + diskspace = getoutput('df -h / | awk "{print $5}"').split('\n')[1] + available = int(float(diskspace.replace(' ','').split('G')[2])*1000) + if available < diskspace_threshold: + save('status_internal_cam', 'Routine-stopping') + return + +def focus(i): + f = focuslist[i] + camera('/v1/camera/picam2_focus?focus=' + str(f)) + if i < len(focuslist) - 1: + i += 1 + else: + i = 0 + return i + +def send_telegram_message(message, telegram_api_token, telegram_client_id): + telegram_bot_path = '/usr/local/bin/send-telegram' + run([telegram_bot_path,"-a",telegram_api_token,"-c",telegram_client_id,"-m",message]) + +if telegram_enable: + telegram_message = "[START] " + hostname + " starting " + projectname + "(" + str(photocount) + " photos) ETA: " + try: + send_telegram_message(telegram_message, telegram_api_token, telegram_client_id) + except Exception as e: + print(e) +for position in coordinates: + counter += 1 + filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + ".jpg" + if load_str('status_internal_cam') == "Routine-stopping": + break + if counter < 6: + ETA = '' + + save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA) + if counter > 6: + check_diskspace() + + move_motor() + sleep(load_float("cam_delay_before")) + + if stacksize ==1: + returning = [counter2] + photo(returning) + counter2 = returning[0] + + else: + photo_stack() + + sleep(load_float("cam_delay_after")) + ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str( + int(photocount / counter * (time() - starttime))) + 's' + + status = { + "projectname": projectname, + "total_photos": photocount, + "current_photo": counter, + "stacksize": steps, + "start_time": int(starttime), + + } + with open('/tmp/status.json', 'w') as status_file: + json.dump(status, status_file) + + position_last = position + +zip.close() +try: + send_telegram_message("[STOP] " + hostname + " stop " + projectname, telegram_api_token, telegram_client_id) +except Exception as e: + print(e) +camera('/v1/camera/picam2_switch_mode?mode=0') + +save('status_internal_cam', 'Routine-done') + +# Delete the status.json file +import os + +try: + os.remove('/tmp/status.json') +except FileNotFoundError: + pass # File doesn't exist, so no need to delete +except Exception as e: + print(f"Error deleting /tmp/status.json: {e}") + + +motorrun('rotor', -position_last[0] ) +motorrun('tt', position_last[1]) + +save('status_internal_cam', '--READY--') + +system('mv ' + zippath + " " + basepath + "scans/" + projectcode + ".zip") + +return msg diff --git a/update/main/settings.js b/update/2024-11S/meanwhile/settings.js similarity index 92% rename from update/main/settings.js rename to update/2024-11S/meanwhile/settings.js index 834f457..357b02b 100644 --- a/update/main/settings.js +++ b/update/2024-11S/meanwhile/settings.js @@ -1,5 +1,5 @@ /** - * Node-RED Settings created at Mon, 24 Jan 2022 08:17:31 GMT + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT * * It can contain any valid JavaScript code that will get run when Node-RED * is started. @@ -19,6 +19,7 @@ * - Node Settings * **/ +process.env.HOSTNAME = require('os').hostname(); module.exports = { @@ -54,7 +55,8 @@ module.exports = { * property can be used */ //userDir: '/home/nol/.node-red/', - userDir: '/home/pi/OpenScan/settings/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + /** Node-RED scans the `nodes` directory in the userDir to find local node files. * The following property can be used to specify an additional directory to scan. */ @@ -137,11 +139,12 @@ module.exports = { * - httpNodeCors * - httpNodeMiddleware * - httpStatic + * - httpStaticRoot ******************************************************************************/ /** the tcp port that the Node-RED web server is listening on */ -// uiPort: process.env.PORT || 1880, -uiPort: process.env.PORT || 80, + uiPort: process.env.PORT || 80, + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. * To listen on all IPv6 addresses, set uiHost to "::", * The following property can be used to listen on a specific interface. For @@ -164,8 +167,8 @@ uiPort: process.env.PORT || 80, * The following property can be used to specify a different root path. * If set to false, this is disabled. */ - //httpAdminRoot: '/admin', -httpAdminRoot: '/editor', + httpAdminRoot: '/editor', + /** The following property can be used to add a custom middleware function * in front of all admin http routes. For example, to set custom http * headers. It can be a single function or an array of middleware functions. @@ -218,9 +221,28 @@ httpAdminRoot: '/editor', /** When httpAdminRoot is used to move the UI to a different root path, the * following property can be used to identify a directory of static content * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot */ - //httpStatic: '/home/nol/node-red-static/', -httpStatic: '/home/pi/OpenScan/', + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + /******************************************************************************* * Runtime Settings * - lang @@ -348,9 +370,9 @@ httpStatic: '/home/pi/OpenScan/', }, codeEditor: { /** Select the text editor component used by the editor. - * Defaults to "ace", but can be set to "ace" or "monaco" + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired */ - lib: "ace", + lib: "monaco", options: { /** The follow options only apply if the editor is set to "monaco" * @@ -360,7 +382,7 @@ httpStatic: '/home/pi/OpenScan/', */ theme: "vs", /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. - * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html */ //fontSize: 14, //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", @@ -405,13 +427,14 @@ httpStatic: '/home/pi/OpenScan/', * will allow the `os` module to be accessed in a Function node using: * global.get("os") */ - functionGlobalContext: { - os:require('os'), - path:require('path'), - fs:require('fs'), - -}, - +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, /** The maximum number of messages nodes will buffer internally as part of their * operation. This applies across a range of nodes that operate on message sequences. * defaults to no limit. A value of 0 also means no limit is applied. @@ -425,8 +448,8 @@ httpStatic: '/home/pi/OpenScan/', * middleware:{function or array}, (req,res,next) - http middleware * ioMiddleware:{function or array}, (socket,next) - socket.io middleware */ - //ui: { path: "ui" }, -ui: { path: "" }, + ui: { path: "" }, + /** Colourise the console output of the debug node */ //debugUseColors: true, diff --git a/update/2024-11S/meanwhile/startup.sh b/update/2024-11S/meanwhile/startup.sh new file mode 100755 index 0000000..bdaad1d --- /dev/null +++ b/update/2024-11S/meanwhile/startup.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +settings_folder="/home/pi/OpenScan/settings" + +# Generate an unique UUID that identifies that OpenScan + +if [ ! -f $settings_folder/openscan_uuid ]; then + echo $(cat /proc/sys/kernel/random/uuid) > $settings_folder/openscan_uuid +fi +echo `cat /proc/cpuinfo|grep Model|cut -d: -f2|awk '{$1=$1};1'` > $settings_folder/architecture +echo `libcamera-still --list-cameras|head -3|tail -1|cut -d: -f2|cut -d[ -f1|awk '{$1=$1};1'` > $settings_folder/camera diff --git a/update/mini/OpenScan.py b/update/2024-11S/stable/OpenScan.py similarity index 50% rename from update/mini/OpenScan.py rename to update/2024-11S/stable/OpenScan.py index 5837204..e634511 100644 --- a/update/mini/OpenScan.py +++ b/update/2024-11S/stable/OpenScan.py @@ -1,5 +1,6 @@ basepath = '/home/pi/OpenScan/' from os.path import isfile +import os def load_bool(name): filename = basepath+'settings/'+name @@ -13,6 +14,72 @@ def load_bool(name): value = False return value +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + return True + def load_str(name): filename = basepath+'settings/'+name if not isfile(filename): @@ -58,19 +125,26 @@ def OpenScanCloud(cmd, msg): def camera(cmd, msg = {}): from requests import get flask = 'http://127.0.0.1:1312/' - r = get(flask + cmd, params=msg) - return r.status_code + try: + r = get(flask + cmd, params=msg) + return r.status_code + except: + return 400 -def motorrun(motor,angle): +def motorrun(motor,angle,ES_enable=False,ES_start_state = True): + #motor can be "rotor", "tt" or "extra" import RPi.GPIO as GPIO from time import sleep from math import cos + msg = {'cmd':'set'} + GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) spr = load_int(motor + '_stepsperrotation') dirpin = load_int('pin_' + motor + '_dir') steppin = load_int('pin_' + motor +'_step') + ES_pin = load_int('pin_' + motor + '_endstop') dir = load_int(motor + '_dir') ramp = load_int(motor + '_accramp') acc = load_float(motor + '_acc') @@ -80,12 +154,23 @@ def motorrun(motor,angle): step_count=int(angle*spr/360) * dir GPIO.setup(dirpin, GPIO.OUT) GPIO.setup(steppin, GPIO.OUT) + GPIO.setup(ES_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP) + if (step_count>0): GPIO.output(dirpin, GPIO.HIGH) if(step_count<0): GPIO.output(dirpin, GPIO.LOW) step_count=-step_count for x in range(step_count): + if ES_enable == True and GPIO.input(ES_pin) != ES_start_state: + i = 0 + while i <= 10: + if GPIO.input(ES_pin) == ES_start_state: + i = 11 + if i == 10: + return + i = i + 1 + GPIO.output(steppin, GPIO.HIGH) if x<=ramp and x<=step_count/2: delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) @@ -101,6 +186,7 @@ def motorrun(motor,angle): def ringlight(number,state): import RPi.GPIO as GPIO + msg = {'cmd':'set'} pin = load_int('pin_ringlight' + str(number)) GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) @@ -113,8 +199,6 @@ def take_photo(file): model=load_str('model') - - shutter = str(load_int('cam_shutter')) saturation = load_str('cam_saturation') contrast = load_str('cam_contrast') @@ -138,8 +222,12 @@ def take_photo(file): else: autofocus = '' - cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + ' >/dev/null 2>&1' -# cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + if camera == "usb_webcam": + cmd = 'fswebcam -i 0 -r "1280x720" -F 5 --no-banner --jpeg 95 --save ' + filepath2 + else: + cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + ' >/dev/null 2>&1' + # cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + system(cmd) return cmd @@ -183,3 +271,42 @@ def create_coordinates(angle_min, angle_max,point_count): point_count=point_count+1 return filtered + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/mini/config.txt b/update/2024-11S/stable/config.txt old mode 100644 new mode 100755 similarity index 94% rename from update/mini/config.txt rename to update/2024-11S/stable/config.txt index fad6e74..4faf2c8 --- a/update/mini/config.txt +++ b/update/2024-11S/stable/config.txt @@ -2,10 +2,8 @@ # http://rpf.io/configtxt # Some settings may impact device functionality. See link above for details - # uncomment if you get no picture on HDMI for a default "safe" mode #hdmi_safe=1 -hdmi_blanking=2 # uncomment the following to adjust overscan. Use positive numbers if console # goes off screen, and negative if there is too much border @@ -55,13 +53,13 @@ hdmi_blanking=2 dtparam=audio=on # Automatically load overlays for detected cameras -camera_auto_detect=0 +camera_auto_detect=1 # Automatically load overlays for detected DSI displays display_auto_detect=1 # Enable DRM VC4 V3D driver -#dtoverlay=vc4-kms-v3d +dtoverlay=vc4-kms-v3d max_framebuffers=2 # Disable compensation for displays with overscan @@ -73,14 +71,14 @@ disable_overscan=1 # (e.g. for USB device mode) or if USB support is not required. otg_mode=1 +[all] + [pi4] # Run as fast as firmware / board allows arm_boost=1 [all] - camera_auto_detect=0 gpu_mem=256 -dtoverlay=vc4-fkms-v3d -dtoverlay=imx519,media-controller=0 dtoverlay=imx519 +#dtoverlay=imx519,media-controller=1 diff --git a/update/2024-11S/stable/fla.py b/update/2024-11S/stable/fla.py new file mode 100644 index 0000000..026867e --- /dev/null +++ b/update/2024-11S/stable/fla.py @@ -0,0 +1,519 @@ +from flask import Flask, request, redirect, send_file, send_from_directory +from flask_restx import Resource, Api, Namespace +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont +from time import sleep, time +from OpenScan import load_int, load_float, load_bool, ringlight, motorrun +import RPi.GPIO as GPIO +from math import sqrt +import os +import math +from skimage import feature, color, transform +import numpy as np +from scipy import ndimage +import socket + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +app = Flask(__name__) +api = Api(app, version='1.0', title='OpenScan API', description='API for OpenScan') + +v1 = Namespace('v1', description='API v1') +# Create a namespace for system operations +system_ns = Namespace('system', description='System operations') +camera_ns = Namespace('camera', description='Camera operations') +motor_ns = Namespace('motor', description='Motor operations') + +api.add_namespace(v1, path='/v1') +api.add_namespace(system_ns, path='/v1/system') +api.add_namespace(camera_ns, path='/v1/camera') +api.add_namespace(motor_ns, path='/v1/motor') + +basedir = '/home/pi/OpenScan/' +timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + + +################################################################################################################### + + +@system_ns.route('/status') +class Status(Resource): + def get(self): + ''' + Get system status + ''' + import os + import json + from time import time + + if os.path.exists('/tmp/status.json'): + try: + with open('/tmp/status.json', 'r') as status_file: + status = json.load(status_file) + + elapsed_time = time() - status['start_time'] + estimated_total_time = (elapsed_time / status['current_photo']) * status['total_photos'] + time_remaining = max(0, estimated_total_time - elapsed_time) + + status.update({ + "status": "running", + "elapsed_time": int(elapsed_time), + "estimated_total_time": int(estimated_total_time), + "time_remaining": int(time_remaining) + }) + + return status, 200 + except Exception as e: + return {"error": f"Error reading status file: {str(e)}"}, 500 + else: + return {"status": "idle"}, 200 + +@system_ns.route('/shutdown') +class Shutdown(Resource): + @system_ns.doc(params={'token': 'Shutdown token for authentication'}) + def get(self): + '''Shutdown the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('shutdown -h now') + return {'message': 'Shutting down'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/reboot') +class Reboot(Resource): + @system_ns.doc(params={'token': 'Reboot token for authentication'}) + def get(self): + '''Reboot the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('reboot -h') + return {'message': 'Rebooting'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/ringlight') +class Ringlight(Resource): + @system_ns.doc(params={'state': 'Ringlight state (0 or 1)'}) + def get(self): + '''Set ringlight state''' + state = int(request.args.get('state')) + if state == 0: + ringlight(1, False) + ringlight(2, False) + else: + ringlight(1, True) + ringlight(2, True) + return {'message': f'Ringlight set to {state}'}, 200 + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) + + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') + + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wait 3-5s + return {'message': 'Auto focus triggered'}, 200 + +@motor_ns.route('/motor_run') +class MotorRun(Resource): + ''' + Run a motor + ''' + @motor_ns.doc(params={ + 'motor': 'Motor name (rotor, tt, extra)', + 'angle': 'Angle to rotate (integer)', + 'ES_enable': 'Enable endstop (optional, boolean)', + 'ES_start_state': 'Endstop start state (optional, boolean)' + }) + @motor_ns.response(400, 'Bad Request') + def get(self): + '''Run a motor''' + motor = request.args.get('motor') + if not motor: + return {'error': 'Motor parameter is required'}, 400 + if motor not in ['rotor', 'tt', 'extra']: + return {'error': 'Invalid motor name'}, 400 + + try: + angle = int(request.args.get('angle')) + except (TypeError, ValueError): + return {'error': 'Angle must be an integer'}, 400 + + ES_enable = request.args.get('ES_enable', 'false').lower() == 'true' + ES_start_state = request.args.get('ES_start_state', 'true').lower() == 'true' + + try: + motorrun(motor, angle, ES_enable, ES_start_state) + except Exception as e: + return {'error': f'Error running motor: {str(e)}'}, 500 + + return {'message': f'Motor {motor} run to {angle} degrees'}, 200 + + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + + +if __name__ == '__main__': +# app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) + app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) + diff --git a/update/2024-11S/stable/flows.json b/update/2024-11S/stable/flows.json new file mode 100644 index 0000000..1c11a12 --- /dev/null +++ b/update/2024-11S/stable/flows.json @@ -0,0 +1,9378 @@ +[ + { + "id": "e6f4d02efb300ea9", + "type": "tab", + "label": "Init", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "481edaf6db5a7a54", + "type": "tab", + "label": "Scan", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "80a3942785a26c29", + "type": "tab", + "label": "Files", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "e43a27722b508115", + "type": "tab", + "label": "Settings", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "a5557543ccff5889", + "type": "tab", + "label": "Update", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", + "type": "ui_tab", + "name": "Scan", + "icon": "dashboard", + "order": 2, + "disabled": false, + "hidden": false + }, + { + "id": "5c06cb6bcc371ee6", + "type": "ui_base", + "theme": { + "name": "theme-dark", + "lightTheme": { + "default": "#0094CE", + "baseColor": "#0094CE", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "darkTheme": { + "default": "#097479", + "baseColor": "#097479", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "customTheme": { + "name": "Untitled Theme 1", + "default": "#4B7930", + "baseColor": "#4B7930", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false + }, + "themeState": { + "base-color": { + "default": "#097479", + "value": "#097479", + "edited": false + }, + "page-titlebar-backgroundColor": { + "value": "#097479", + "edited": false + }, + "page-backgroundColor": { + "value": "#111111", + "edited": false + }, + "page-sidebar-backgroundColor": { + "value": "#333333", + "edited": false + }, + "group-textColor": { + "value": "#0eb8c0", + "edited": false + }, + "group-borderColor": { + "value": "#555555", + "edited": false + }, + "group-backgroundColor": { + "value": "#333333", + "edited": false + }, + "widget-textColor": { + "value": "#eeeeee", + "edited": false + }, + "widget-backgroundColor": { + "value": "#097479", + "edited": false + }, + "widget-borderColor": { + "value": "#333333", + "edited": false + }, + "base-font": { + "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + } + }, + "angularTheme": { + "primary": "indigo", + "accents": "blue", + "warn": "red", + "background": "grey", + "palette": "light" + } + }, + "site": { + "name": "OpenScan", + "hideToolbar": "false", + "allowSwipe": "false", + "lockMenu": "false", + "allowTempTheme": "true", + "dateFormat": "DD/MM/YYYY", + "sizes": { + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, + "cx": 6, + "cy": 6, + "px": 0, + "py": 0 + } + } + }, + { + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 6 + }, + { + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 5 + }, + { + "id": "b5fdd57b.15eda8", + "type": "ui_group", + "name": "Main", + "tab": "15a222ed.d70a7d", + "order": 1, + "disp": false, + "width": 13, + "collapse": false + }, + { + "id": "db43d646.2074c8", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", + "order": 2, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "15a222ed.d70a7d", + "type": "ui_tab", + "name": "Files&Cloud", + "icon": "dashboard", + "order": 3, + "disabled": false, + "hidden": false + }, + { + "id": "365a30d0dfa83e95", + "type": "ui_group", + "name": "settings", + "tab": "e23b837a9f040895", + "order": 1, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "ac7409105cfecac6", + "type": "ui_group", + "name": "advanced", + "tab": "e23b837a9f040895", + "order": 3, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "729f9ea6e3513c9b", + "type": "ui_group", + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "5b3e5aca21140e9a", + "type": "ui_group", + "name": "Update", + "tab": "b3150b13e34b1fe8", + "order": 1, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "b3150b13e34b1fe8", + "type": "ui_tab", + "name": "OpenScan", + "icon": "dashboard", + "order": 1, + "disabled": false, + "hidden": true + }, + { + "id": "ddbd496e.93a288", + "type": "ui_group", + "name": "Manage Updates", + "tab": "d25e08b4.5b27e8", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "3ce32450.e0cffc", + "type": "ui_group", + "name": "System & Stats", + "tab": "d25e08b4.5b27e8", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "d25e08b4.5b27e8", + "type": "ui_tab", + "name": "Update & Info", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "4390b2ebcbbe104c", + "type": "ui_group", + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "8ab79a98e536e0d6", + "type": "ui_group", + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Motor", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 1, + "width": 1, + "height": 1 + }, + { + "id": "33b6d7317d1524b8", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "aaf5b874c52a58aa", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, + "height": 1 + }, + { + "id": "f8d8740dcbf499fb", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 11, + "width": 1, + "height": 1 + }, + { + "id": "7ac0cb556740d159", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, + "height": 1 + }, + { + "id": "4de2414e29020c74", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "90223f7ddc082321", + "order": 2, + "width": 7, + "height": 1 + }, + { + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 + }, + { + "id": "ce21673092264c38", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, + "height": 1 + }, + { + "id": "3f7b77f8a1675d27", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "12b719cba49817c9", + "order": 7, + "width": 4, + "height": 1 + }, + { + "id": "0799b02d12fc3a14", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "7a3279eea439bcdd", + "order": 25, + "width": 6, + "height": 1 + }, + { + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 460, + "wires": [ + [ + "949bafced17d66d6" + ] + ] + }, + { + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 460, + "wires": [ + [] + ] + }, + { + "id": "a1f0ed7d5a9d670e", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.1", + "topic": "", + "x": 110, + "y": 60, + "wires": [ + [ + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6" + ] + ] + }, + { + "id": "544d20f02215011a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 60, + "wires": [ + [ + "c77552216a8bb781" + ] + ] + }, + { + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 540, + "y": 60, + "wires": [ + [ + "960912e90ba5b5bc" + ] + ] + }, + { + "id": "960912e90ba5b5bc", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244" + ], + "x": 645, + "y": 60, + "wires": [] + }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "168d72a54504b327", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "5/0.1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "5", + "topic": "", + "payload": "", + "payloadType": "str", + "x": 100, + "y": 380, + "wires": [ + [ + "6c6ef2255a7d39e5" + ] + ] + }, + { + "id": "6c6ef2255a7d39e5", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "repeat 5s/0.1s", + "mode": "link", + "links": [ + "61990987acd0f263", + "2415272f42ce468c", + "6bf8344af427a6ba" + ], + "x": 205, + "y": 380, + "wires": [] + }, + { + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", + "outputs": 1, + "x": 270, + "y": 140, + "wires": [ + [ + "eb1a2387a1eeea76" + ] + ] + }, + { + "id": "b1e2491c952f84c9", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, + "wires": [ + [ + "200d4b9951b6e066" + ] + ] + }, + { + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf", + "65518f3d4e3095e5" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 800, + "y": 40, + "wires": [ + [ + "544d20f02215011a" + ] + ] + }, + { + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 580, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", + "outputs": 1, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 540, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 620, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 580, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 660, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "8955d11554f55e63", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "5b3e5aca21140e9a", + "order": 1, + "width": 6, + "height": 3, + "passthru": false, + "label": "Install Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "date", + "topic": "", + "topicType": "str", + "x": 120, + "y": 720, + "wires": [ + [ + "1e7457ea9c2c5e09" + ] + ] + }, + { + "id": "1e7457ea9c2c5e09", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "update", + "mode": "link", + "links": [ + "39a502b38837273d" + ], + "x": 245, + "y": 720, + "wires": [] + }, + { + "id": "245e4341d4fb611c", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 790, + "y": 540, + "wires": [ + [ + "627406f3611511dc" + ] + ] + }, + { + "id": "627406f3611511dc", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "write", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 930, + "y": 540, + "wires": [ + [ + "50eeb3e362f9027f" + ] + ] + }, + { + "id": "88b1bddde110298a", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 650, + "y": 540, + "wires": [ + [ + "245e4341d4fb611c" + ] + ] + }, + { + "id": "50eeb3e362f9027f", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244" + ], + "x": 1015, + "y": 540, + "wires": [] + }, + { + "id": "4f3121f158f06a61", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", + "outputs": 1, + "x": 860, + "y": 580, + "wires": [ + [] + ] + }, + { + "id": "4a8a04b1e5dca8fe", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "run rotor till endstop", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 690, + "y": 580, + "wires": [ + [ + "4f3121f158f06a61" + ] + ] + }, + { + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n
    \n
  • speed improvement 2-3x
  • \n
  • currently tested on OpenScan Mini + IMX519 with RPi 4
  • \n
  • optimized toolpath
  • \n
  • more responsive user interface
  • \n
  • hotspot mode (when no wireless network available ssid: openscan pw: opensource
  • \n
  • preview features and sharpness
  • \n
  • partial background masking
  • \n
  • no more autofocus --> instead you can set a min and max focus distance
  • \n
\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 580, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "6a3d9acbe097a3d2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 120, + "wires": [ + [ + "cb6ebdabaaf7d0da" + ] + ] + }, + { + "id": "7ef6f1b5c67201fe", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "86f7d1b2d763f6e2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 160, + "wires": [ + [ + "c8a3fde5206ce1ae" + ] + ] + }, + { + "id": "fd799c931139764d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 240, + "wires": [ + [ + "87be854db758a9a6" + ] + ] + }, + { + "id": "d5140d455122c49a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 280, + "wires": [ + [ + "9daea4bd57f7a00e" + ] + ] + }, + { + "id": "194f3590dd4f6e3d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "2de69452e829d780", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", + "label": "", + "tooltip": "", + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, + "height": 1, + "passthru": true, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 320, + "y": 80, + "wires": [ + [ + "734ac3bff2df6837" + ] + ] + }, + { + "id": "97170908e1f4ac55", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 80, + "wires": [ + [ + "58e565fea35cb667" + ] + ] + }, + { + "id": "734ac3bff2df6837", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 55, + "y": 80, + "wires": [ + [ + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" + ] + ] + }, + { + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/v1/camera/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", + "outputs": 1, + "x": 510, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "c7f5808d753480d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 170, + "y": 200, + "wires": [ + [ + "11f41a6030578ef4" + ] + ] + }, + { + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 200, + "wires": [ + [ + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "855cbcadef1163c5", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 840, + "wires": [ + [ + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" + ] + ] + }, + { + "id": "1a443e20a973d2f1", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw true", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 630, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "d1b87196ae5373ed", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw false", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 430, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "03d92601c62b79d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "4s/0.5", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "Repeat", + "payload": "0.1", + "payloadType": "str", + "x": 100, + "y": 840, + "wires": [ + [ + "855cbcadef1163c5" + ] + ] + }, + { + "id": "41e6a4649b6afbfb", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Take Preview Shot", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/v1/camera/picam2_take_photo')\n\nreturn msg\n", + "outputs": 1, + "x": 450, + "y": 800, + "wires": [ + [ + "1a443e20a973d2f1", + "296636b7467fc745" + ] + ] + }, + { + "id": "85a268108250ba88", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", + "order": 1, + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 450, + "y": 840, + "wires": [ + [ + "417f653ca0dfdcfc", + "180476141c2a44ad" + ] + ] + }, + { + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, + "wires": [] + }, + { + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, + "wires": [ + [ + "e864254b18c23dd1" + ] + ] + }, + { + "id": "e864254b18c23dd1", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int\n\nif 'payload' not in msg:\n return\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'))\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'))\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'))\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'))\n\n", + "outputs": 1, + "x": 780, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "180476141c2a44ad", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 880, + "wires": [ + [ + "8cbdbfecbd12ef83" + ] + ] + }, + { + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", + "outputs": 1, + "x": 870, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", + "outputs": 1, + "x": 440, + "y": 720, + "wires": [ + [ + "923be3b2b25224b4" + ] + ] + }, + { + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "c8a3fde5206ce1ae", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 160, + "wires": [ + [ + "034ec9f59e50a361", + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "034ec9f59e50a361", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, + "wires": [ + [ + "194f3590dd4f6e3d" + ] + ] + }, + { + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, + "wires": [ + [ + "2de69452e829d780" + ] + ] + }, + { + "id": "cb6ebdabaaf7d0da", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 120, + "wires": [ + [ + "7ef6f1b5c67201fe" + ] + ] + }, + { + "id": "82ecd3cd971cb7ea", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, + "height": 1, + "name": "projectname", + "label": "Projectname", + "format": "", + "layout": "row-left", + "className": "", + "x": 530, + "y": 40, + "wires": [] + }, + { + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, + "wires": [ + [ + "06e1e19835a9816e" + ] + ] + }, + { + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, + "wires": [ + [ + "1fe18f3b0b52aabd" + ] + ] + }, + { + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "7dd287f40385922f", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "start ", + "group": "365a30d0dfa83e95", + "order": 10, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-play", + "payload": "", + "payloadType": "date", + "topic": "enabled", + "topicType": "str", + "x": 130, + "y": 1040, + "wires": [ + [ + "33d94a04b96a2de0", + "6d15f717d5a11002", + "9a6b30a0175a8ecd" + ] + ] + }, + { + "id": "579f2211199fd6ab", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "stop", + "group": "365a30d0dfa83e95", + "order": 12, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-stop", + "payload": "numberofphotos", + "payloadType": "global", + "topic": "", + "topicType": "str", + "x": 490, + "y": 1100, + "wires": [ + [ + "1787f08ed7070ddd", + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "1787f08ed7070ddd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "stop", + "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "outputs": 1, + "x": 630, + "y": 1100, + "wires": [ + [] + ] + }, + { + "id": "e9b13dfd9f8d3711", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 395, + "y": 1000, + "wires": [] + }, + { + "id": "9654deebb668e012", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 290, + "y": 1140, + "wires": [ + [ + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "8367cfa0bf5bc5df", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine", + "links": [ + "200d4b9951b6e066", + "8689e938.dd9e38", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 45, + "y": 1040, + "wires": [ + [ + "7dd287f40385922f" + ] + ] + }, + { + "id": "fb13752beddee9f2", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 535, + "y": 1060, + "wires": [] + }, + { + "id": "33d94a04b96a2de0", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1100, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "c1c044f3c2139f68", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 1140, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "1daf9e3a5bd5ab48", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 430, + "y": 1040, + "wires": [ + [ + "fb13752beddee9f2" + ] + ] + }, + { + "id": "6d15f717d5a11002", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 1000, + "wires": [ + [ + "e9b13dfd9f8d3711" + ] + ] + }, + { + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "# The contents of this file are embedded in the OpenScan app (Node-RED)\nfrom OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\n\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\nimport json\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/v1/camera/picam2_switch_mode?mode=1')\n\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nif load_bool('rotor_enable_endstop'):\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True, False)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/v1/camera/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/v1/camera/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\n\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n\n motorrun('rotor',rotor_angle)\n motorrun('tt',tt_angle)\n \n return\n\n # THE FOLLOWING DOES NOT WORK PROPERLY WITH THREADING ?!\n\n #tt_thread = threading.Thread(target=motorrun, args=('tt', tt_angle))\n #rotor_thread = threading.Thread(target=motorrun, args=('rotor', rotor_angle))\n #tt_thread.start()\n #rotor_thread.start()\n #tt_thread.join()\n #rotor_thread.join()\n\n\ncounter2 = 0\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/v1/camera/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n \n # Calculate time remaining and write status to /tmp/status as JSON\n elapsed_time = time() - starttime\n estimated_total_time = (elapsed_time / counter) * photocount * steps\n time_remaining = max(0, estimated_total_time - elapsed_time)\n \n status = {\n \"scan_name\": projectname,\n \"total_photos\": photocount,\n \"current_photo\": counter,\n \"stacksize\": steps,\n \"start_time\": int(starttime),\n }\n with open('/tmp/status.json', 'w') as status_file:\n json.dump(status, status_file)\n\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/v1/camera/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\n# Delete the status.json file\nimport os\n\ntry:\n os.remove('/tmp/status.json')\nexcept FileNotFoundError:\n pass # File doesn't exist, so no need to delete\nexcept Exception as e:\n print(f\"Error deleting /tmp/status.json: {e}\")\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\n\nsystem('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, + "wires": [ + [ + "1daf9e3a5bd5ab48", + "795c85ad4f109567" + ] + ] + }, + { + "id": "afe47a9eaae6f67f", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, + "height": 1, + "name": "", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", + "className": "", + "x": 340, + "y": 40, + "wires": [] + }, + { + "id": "8608517d0567d63f", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 40, + "wires": [ + [ + "afe47a9eaae6f67f" + ] + ] + }, + { + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 55, + "y": 40, + "wires": [ + [ + "8608517d0567d63f" + ] + ] + }, + { + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, + "wires": [ + [ + "9774e7ad3b506354" + ] + ] + }, + { + "id": "9774e7ad3b506354", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 380, + "wires": [ + [ + "f0af909f3e739b22" + ] + ] + }, + { + "id": "39c744466a21735e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 40, + "wires": [ + [ + "fa181d22775c2ce6" + ] + ] + }, + { + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 80, + "wires": [ + [ + "c615034ea6b26174" + ] + ] + }, + { + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 480, + "wires": [ + [ + "237c2135cdad86ea" + ] + ] + }, + { + "id": "dd7fb8791d34c751", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 880, + "wires": [ + [ + "180476141c2a44ad" + ] + ] + }, + { + "id": "5baf89a2682265f7", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "enable led", + "links": [ + "eb1a2387a1eeea76" + ], + "x": 145, + "y": 880, + "wires": [ + [ + "dd7fb8791d34c751" + ] + ] + }, + { + "id": "6a26e8a7253d708c", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 40, + "wires": [ + [ + "39c744466a21735e" + ] + ] + }, + { + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, + "wires": [ + [ + "61aab497fa50898e" + ] + ] + }, + { + "id": "9fd259de91de1da1", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 735, + "y": 40, + "wires": [ + [ + "6a26e8a7253d708c", + "35ad7e55833836c1" + ] + ] + }, + { + "id": "fa181d22775c2ce6", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 40, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "c615034ea6b26174", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 80, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "ae5ee8787145906d", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import camera\ncamera('/v1/camera/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", + "outputs": 1, + "x": 1290, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "f0af909f3e739b22", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Features", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 420, + "wires": [ + [ + "710fc2dbb5ef0167" + ] + ] + }, + { + "id": "710fc2dbb5ef0167", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "d93c2b67bcf23b9a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 480, + "wires": [ + [ + "5e83b653850fa16e" + ] + ] + }, + { + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 95, + "y": 480, + "wires": [ + [ + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" + ] + ] + }, + { + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "c8b93b42c720b9cf", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", + "links": [ + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" + ], + "x": 85, + "y": 380, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 620, + "y": 1000, + "wires": [] + }, + { + "id": "ea54fcc2.cfcc2", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "get dirs", + "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "outputs": 1, + "x": 480, + "y": 180, + "wires": [ + [ + "f3662f8c7d3d7a2d", + "01e4783e148c6698" + ] + ] + }, + { + "id": "2f4c0f98.dee2", + "type": "link in", + "z": "80a3942785a26c29", + "name": "filelist", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "a4f09e25.02569", + "ed35109311335099", + "fb13752beddee9f2" + ], + "x": 355, + "y": 220, + "wires": [ + [ + "ea54fcc2.cfcc2" + ] + ] + }, + { + "id": "952ce286.4ffd4", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 4, + "width": 6, + "height": 1, + "name": "Status", + "label": "Status", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 250, + "y": 60, + "wires": [] + }, + { + "id": "d4383424.7807c8", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "upload", + "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", + "outputs": 2, + "x": 530, + "y": 460, + "wires": [ + [ + "9a132ab1.b21658" + ], + [ + "3d16b3789632784d", + "9a132ab1.b21658" + ] + ] + }, + { + "id": "50710948.71c308", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "set", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 750, + "y": 180, + "wires": [ + [ + "ada1b6f7cccc9344", + "85839a17fb7b58b9" + ] + ] + }, + { + "id": "834046a4.647938", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 5, + "width": 6, + "height": 1, + "name": "Set", + "label": "Set:", + "format": "{{msg.payload.Name}}", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 220, + "wires": [] + }, + { + "id": "9a132ab1.b21658", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.true", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 780, + "y": 460, + "wires": [ + [ + "8689e938.dd9e38" + ] + ] + }, + { + "id": "3c67e97b.9d19a6", + "type": "function", + "z": "80a3942785a26c29", + "name": "enable", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 130, + "y": 340, + "wires": [ + [ + "7a93d1e18254685c", + "e434ef42bd6b92e8", + "d5d840183025d91b", + "ab9e90ab5a53a0dd", + "478994f671a3907d" + ] + ] + }, + { + "id": "bfc01f26.c32cf", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.false", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 500, + "wires": [ + [ + "f20f2dbc.0f123" + ] + ] + }, + { + "id": "b33d604c.5f1a6", + "type": "link in", + "z": "80a3942785a26c29", + "name": "enable cloud", + "links": [ + "4082b136.dae18", + "8689e938.dd9e38", + "bd75f33b8a57c522", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 35, + "y": 340, + "wires": [ + [ + "3c67e97b.9d19a6" + ] + ] + }, + { + "id": "f6bd1a04.470838", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "set", + "tot": "global" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 410, + "y": 460, + "wires": [ + [ + "d4383424.7807c8" + ] + ] + }, + { + "id": "4082b136.dae18", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "b33d604c.5f1a6", + "87574a42938afec4" + ], + "x": 715, + "y": 140, + "wires": [] + }, + { + "id": "f20f2dbc.0f123", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 515, + "y": 500, + "wires": [] + }, + { + "id": "8689e938.dd9e38", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 875, + "y": 460, + "wires": [] + }, + { + "id": "15de0ebb.616d61", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 380, + "wires": [ + [ + "a7d89487.ee8858" + ] + ] + }, + { + "id": "a7d89487.ee8858", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", + "outputs": 1, + "x": 690, + "y": 380, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "a4f09e25.02569", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2" + ], + "x": 775, + "y": 360, + "wires": [] + }, + { + "id": "7a93d1e18254685c", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "92c98e6ce7cd25f9" + ], + "x": 235, + "y": 500, + "wires": [] + }, + { + "id": "4d99c601c9881680", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "refresh", + "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", + "outputs": 2, + "x": 320, + "y": 180, + "wires": [ + [ + "ea54fcc2.cfcc2", + "b42e061fb1f1f3d7" + ], + [ + "6434e713f088012b" + ] + ] + }, + { + "id": "372e95797a3f2f3b", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "limit :)", + "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", + "outputs": 1, + "x": 90, + "y": 220, + "wires": [ + [ + "573edbfdb7500ddc" + ] + ] + }, + { + "id": "573edbfdb7500ddc", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 230, + "y": 220, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "dacb1f078b624e10", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 340, + "wires": [ + [ + "c8d65cc7c2ff7c36" + ] + ] + }, + { + "id": "92c98e6ce7cd25f9", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "7a93d1e18254685c", + "bd75f33b8a57c522" + ], + "x": 35, + "y": 180, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "3d16b3789632784d", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 770, + "y": 500, + "wires": [ + [] + ] + }, + { + "id": "6434e713f088012b", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 470, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "c8d65cc7c2ff7c36", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", + "outputs": 1, + "x": 690, + "y": 340, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "f4e9a4bd79b4221f", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 340, + "wires": [ + [ + "dacb1f078b624e10" + ] + ] + }, + { + "id": "2806bf08ea21216d", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 380, + "wires": [ + [ + "15de0ebb.616d61" + ] + ] + }, + { + "id": "61990987acd0f263", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 45, + "y": 60, + "wires": [ + [ + "51579603bce21e98" + ] + ] + }, + { + "id": "e8e488a6dd5d0b33", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "Download", + "order": 8, + "width": 3, + "height": 1, + "format": "\n
Download\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 880, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "0c387c0291d6c131", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 750, + "y": 260, + "wires": [ + [ + "e8e488a6dd5d0b33" + ] + ] + }, + { + "id": "e5f38b4a07a5e278", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 655, + "y": 220, + "wires": [ + [ + "834046a4.647938" + ] + ] + }, + { + "id": "e434ef42bd6b92e8", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "upload2", + "order": 7, + "width": 3, + "height": 1, + "format": "upload", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 460, + "wires": [ + [ + "f6bd1a04.470838" + ] + ] + }, + { + "id": "c46e10b9c201913e", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "refresh", + "order": 2, + "width": 4, + "height": 1, + "format": "refresh{{msg.text}}", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 160, + "y": 180, + "wires": [ + [ + "372e95797a3f2f3b", + "4d99c601c9881680" + ] + ] + }, + { + "id": "d5d840183025d91b", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del set", + "order": 11, + "width": 2, + "height": 1, + "format": "delete set", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 380, + "wires": [ + [ + "2806bf08ea21216d" + ] + ] + }, + { + "id": "ab9e90ab5a53a0dd", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del ", + "order": 10, + "width": 2, + "height": 1, + "format": "delete all", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 340, + "wires": [ + [ + "f4e9a4bd79b4221f" + ] + ] + }, + { + "id": "478994f671a3907d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "combine", + "order": 9, + "width": 2, + "height": 1, + "format": "combine", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 540, + "wires": [ + [ + "51bfd0fb7b1d292e" + ] + ] + }, + { + "id": "189c1eed09624a7b", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 580, + "wires": [ + [ + "1493398979a63775" + ] + ] + }, + { + "id": "51bfd0fb7b1d292e", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 420, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "da325be8e74179be", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", + "outputs": 1, + "x": 560, + "y": 580, + "wires": [ + [ + "ed35109311335099" + ] + ] + }, + { + "id": "ed35109311335099", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "2f4c0f98.dee2" + ], + "x": 655, + "y": 580, + "wires": [] + }, + { + "id": "1493398979a63775", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Combine", + "x": 420, + "y": 580, + "wires": [ + [ + "da325be8e74179be" + ] + ] + }, + { + "id": "ada1b6f7cccc9344", + "type": "link out", + "z": "80a3942785a26c29", + "name": "combine", + "mode": "link", + "links": [ + "6dd356510c446cf4" + ], + "x": 835, + "y": 180, + "wires": [] + }, + { + "id": "6dd356510c446cf4", + "type": "link in", + "z": "80a3942785a26c29", + "name": "combine", + "links": [ + "ada1b6f7cccc9344" + ], + "x": 175, + "y": 580, + "wires": [ + [ + "189c1eed09624a7b" + ] + ] + }, + { + "id": "b42e061fb1f1f3d7", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "397ab7f44b893c89", + "3876d5cbd248592b" + ], + "x": 435, + "y": 140, + "wires": [] + }, + { + "id": "b99505440832439f", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "diskspace", + "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", + "outputs": 1, + "x": 800, + "y": 100, + "wires": [ + [ + "92047434f8e9f927" + ] + ] + }, + { + "id": "92047434f8e9f927", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 950, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "f3662f8c7d3d7a2d", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "minute", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 650, + "y": 100, + "wires": [ + [ + "b99505440832439f" + ] + ] + }, + { + "id": "51579603bce21e98", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "read", + "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", + "outputs": 1, + "x": 130, + "y": 60, + "wires": [ + [ + "952ce286.4ffd4" + ] + ] + }, + { + "id": "9a5baae623355f9d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "preview", + "order": 6, + "width": 6, + "height": 6, + "format": "
\n\n\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1020, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "85839a17fb7b58b9", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "preview", + "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", + "outputs": 1, + "x": 880, + "y": 220, + "wires": [ + [ + "9a5baae623355f9d" + ] + ] + }, + { + "id": "01e4783e148c6698", + "type": "ui_table", + "z": "80a3942785a26c29", + "group": "b5fdd57b.15eda8", + "name": "", + "order": 1, + "width": 13, + "height": 7, + "columns": [ + { + "field": "Date", + "title": "Date", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Name", + "title": "Name", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Photos", + "title": "Photos", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Duration", + "title": "ΔT", + "width": "60", + "align": "left", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Size", + "title": "Size", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Status", + "title": "Status", + "width": "140", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + } + ], + "outputs": 1, + "cts": true, + "x": 610, + "y": 180, + "wires": [ + [ + "4082b136.dae18", + "50710948.71c308", + "834046a4.647938", + "0c387c0291d6c131" + ] + ] + }, + { + "id": "cb3437ec113e1b6f", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "SSH", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 3, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 390, + "y": 360, + "wires": [ + [ + "c24f61b87e3226dd" + ] + ] + }, + { + "id": "60fd0adce1cfeb82", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Samba", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "test2", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 400, + "wires": [ + [ + "441d3ef525e901da" + ] + ] + }, + { + "id": "c24f61b87e3226dd", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "ssh", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", + "outputs": 1, + "x": 530, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "c013e836e759a085", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "4390b2ebcbbe104c", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "label": "Terms Of Use", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 120, + "y": 320, + "wires": [ + [ + "b78346ca3ce70c68" + ] + ] + }, + { + "id": "f0d8dbcca76a1926", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "Agree", + "cancel": "Disagree", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 410, + "y": 320, + "wires": [ + [ + "e95b86cbac1b03b9" + ] + ] + }, + { + "id": "34374044c0030625", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "General", + "group": "4390b2ebcbbe104c", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

General Settings

Terms Of Use

In order to use the OpenScanCloud, please read the terms of use as files will be transmitted from your device to the OpenScan Servers.

SSH

SSH can be used to access the Raspberry Pi and modify core files of the operating system. Please deactivate, if you do not want to use this feature.

If you want to use it, the default user is pi, password: raspberry. Please change the password immediately. 

Samba

Samba s a network local file sharing server, which allows accessing the Raspberry Pi's file system through the explorer (and other programs like FileZilla). You can use it to transfer custom photo sets to the device in order to use the OpenScanCloud. Therefore, you need to transfer the zip file containing your photos to the following folder /OpenScan/scans/

You can access the Raspberry Pis file system by inserting the following line into your Windows explorer: 

\\\\OpenScan/PiShare/OpenScan/scans/

username: pi, password: raspberry

Please deactivate the local file sharing if you do not intend to use it

Advanced Settings

Enable a ton of additional settings, which should be changed only if you know what you are doing ;)

Model

Device model you are using: OpenScan Mini or OpenScan Classic. Setting the device affects the settings of the motor (gear ratio, acceleration, speed). You can change those values manually in the advanced settings.

Camera

A wide range of camera modules is supported (Pi camera v1.3, v2.1, HQ, Arducam IMX519, IMX290, IMX378, OV9281). If you encounter any issues with those models, please check the orientation of the camera ribbon cable and its connectors.

DSLR (gphoto) - connect a wide range of DSLR cameras to the device through USB. See GPhoto for a full list of supported devices.

External camera - triggering any camera through an isolated GPIO signal on the front side of the pi shield.

Shutdown/Reboot

Always use the shutdown button before you power off your Raspberry Pi.

Restore Default Settings

In case you want to restore the default settings

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "b2b6bf23c9989133", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Pinout", + "group": "70d0be671bf03ca7", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Pinout

ONLY CHANGE THE PINOUT IF YOU ARE ABSOLUTELY SURE! CHANGES CAN DAMAGE THE RASPBERRY PI AND ANY PERIPHERALS!


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "441d3ef525e901da", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "smb", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", + "outputs": 1, + "x": 530, + "y": 400, + "wires": [ + [] + ] + }, + { + "id": "3256bab150113a48", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Motor", + "group": "7a3279eea439bcdd", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Motor Settings

Turntable Mode

Activate turntable mode in order to deactivate the rotor. The routine will only move the turntable and take a given number of photos.

Rotor - Start Angle, Min and Max Angle

Since this version of OpenScan does not have an endstop (yet), it is necessary to tell the device its position when the routine is being started. 0° corresponds to the horizontal (natural) orientation.

After that, the device will equally space the image positions between angle min and angle max.

Rotor/Turntable

Steps per rotation -  defines the number of steps it takes to move the axis 360°. It is defined by A*B*C, where A is the number of steps for one revolution of the given stepper motor (normally 200), B is the microstepping used (normally 16), and C the gear ratio (1 for the turntable and 15 or 5,33 for the OpenScan Mini and Classic respectively)

Delay - time in microseconds between each step of the motor. Lower this value if the movement is too fast

Acceleration - a factor defining how fast the delay time between each step is being changed during acceleration and deceleration phases. Lower this value in order to make the movement smoother.

Acceleration ramp - the number of steps allowed for the acceleration processes. Increase this value, if you want smoother movement.

Manual Angle - Defines the degree value for the manual movement through the arrow buttons in the scan menu

Direction - If needed, reverse the movement (in case the arrow buttons and movement do not correspond). Alternatively, you can flip the motor cable 180° (BUT MAKE SURE TO POWER OFF THE DEVICE!)


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 140, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "7a186669a17daa71", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "camera", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Camera Settings

Jpeg quality

Value in percent, which usually does not need to be changed.

Downscale Preview

The preview image has to be scaled down depending on your network speed. If you want to have a higher quality preview image, you can increase this value, which defines the maximal width/height value. If the value is too high, the preview window might not update

Image Rotation

Change the image rotation, if needed.

Timeout

Defines the time in seconds, when the libcamera command (used for the camera modules) will timeout. Increase this value, if the camera does not get triggered in each position.

Delay Before/After

A fixed delay in seconds before and/or after a photo is taken. Increase this value when the photos have visual motion blur.

AWBG, Gain, Contrast, Saturation

Under most circumstances, you do not need to touch these values.

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 420, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "edac7dd292e7e486", + "type": "comment", + "z": "e43a27722b508115", + "name": "General Settings", + "info": "", + "x": 120, + "y": 280, + "wires": [] + }, + { + "id": "161b52034e578ee2", + "type": "comment", + "z": "e43a27722b508115", + "name": "Network", + "info": "", + "x": 100, + "y": 720, + "wires": [] + }, + { + "id": "f6d6cc35679ede63", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "more sets", + "label": "Advanced Settings", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 480, + "wires": [ + [ + "f06a7bcad524e9f9" + ] + ] + }, + { + "id": "29745a36fc157f3f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "more sets", + "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", + "outputs": 2, + "x": 820, + "y": 480, + "wires": [ + [ + "8750ad979e9ea246" + ], + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "bf23328f9fb11b22", + "type": "ui_ui_control", + "z": "e43a27722b508115", + "name": "change visibility", + "events": "all", + "x": 600, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "b37be1d222bc70c9", + "type": "inject", + "z": "e43a27722b508115", + "name": "1s_repeater", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "1", + "crontab": "", + "once": true, + "onceDelay": "2", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 150, + "y": 60, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "89eedf29b404f750", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, + "wires": [ + [ + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" + ] + ] + }, + { + "id": "2050de5d9e02f69f", + "type": "comment", + "z": "e43a27722b508115", + "name": "Info Texts", + "info": "", + "x": 100, + "y": 140, + "wires": [] + }, + { + "id": "ded3086945a6d4b5", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "check ip address", + "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", + "outputs": 1, + "x": 250, + "y": 940, + "wires": [ + [ + "3cfe464506f46ecd" + ] + ] + }, + { + "id": "3cfe464506f46ecd", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Your local IP:", + "format": "{{msg.ip}}", + "layout": "row-spread", + "className": "", + "x": 430, + "y": 940, + "wires": [] + }, + { + "id": "bd206ad109831e6a", + "type": "comment", + "z": "e43a27722b508115", + "name": "OpenScanCloud", + "info": "", + "x": 120, + "y": 1260, + "wires": [] + }, + { + "id": "b70a9a665c1e4d36", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Cloud-settings", + "group": "12b719cba49817c9", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

OpenScanCloud

OpenScanCloud is a free/donation-based cloud processing service, which will convert your photos into 3d models using latest photogrammetry technology. Feel free to support the project with a small donation at BuyMeACoffee.

The only requirement to use this service is a one-time, free-of-charge registration (which is solely an anti-spam measure). By filling out the registration form, you will receive an individual access token.

Register

In order to use the OpenScanCloud, you will have to enter your name and email. It might take 1-3 days to create the access token, which will be sent to your mail address. Please check your spam folder.

Enter Token

Please enter your individual token here in order to activate the cloud functionality. The token will be verified immediately. In case of any problems, please contact cloud@openscan.eu

Token

A shorted version of your token will be displayed here. Please include a copy of this shorted token in any support requests cloud@openscan.eu

Credit (GB)

Each token comes with a given amount of 'credit' which is another measure against spam. The given number in Gigabyte indicates the amount of data, that you can process on the servers. 

IMPORTANT: The credit can be increased at any time by sending a (nice) mail to cloud@openscan.eu

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 260, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "c9f0566601a3e130", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Number of Photos:", + "format": "{{msg.limit_photos}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 1400, + "wires": [] + }, + { + "id": "9bd86d27ea499a2a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Filesize (GB):", + "format": "{{msg.limit_filesize}}", + "layout": "row-spread", + "className": "", + "x": 390, + "y": 1440, + "wires": [] + }, + { + "id": "2c37f7030810d234", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Credit (GB):", + "format": "{{msg.credit}}", + "layout": "row-spread", + "className": "", + "x": 370, + "y": 1480, + "wires": [] + }, + { + "id": "f40286c18afd4501", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "save", + "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", + "outputs": 2, + "x": 750, + "y": 1340, + "wires": [ + [ + "455a5266017ea121", + "50f73cee213ec05c" + ], + [ + "264eece408043021" + ] + ] + }, + { + "id": "455a5266017ea121", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 890, + "y": 1300, + "wires": [ + [] + ] + }, + { + "id": "c368df68593bc2bf", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Token", + "tooltip": "", + "group": "12b719cba49817c9", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 350, + "y": 1360, + "wires": [ + [ + "18fd1afa768187b3" + ] + ] + }, + { + "id": "18fd1afa768187b3", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "Save?", + "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", + "outputs": 2, + "x": 470, + "y": 1360, + "wires": [ + [ + "418aea2ec65573a0" + ], + [ + "9792c89c5f4429f9" + ] + ] + }, + { + "id": "f90a98899b7a71d0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "text", + "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", + "outputs": 1, + "x": 230, + "y": 1360, + "wires": [ + [ + "c368df68593bc2bf" + ] + ] + }, + { + "id": "b4c843620c251c43", + "type": "link in", + "z": "e43a27722b508115", + "name": "token", + "links": [ + "960912e90ba5b5bc", + "50f73cee213ec05c", + "9792c89c5f4429f9", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1360, + "wires": [ + [ + "f90a98899b7a71d0" + ] + ] + }, + { + "id": "418aea2ec65573a0", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 1340, + "wires": [ + [ + "f40286c18afd4501" + ] + ] + }, + { + "id": "9792c89c5f4429f9", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "b4c843620c251c43" + ], + "x": 555, + "y": 1380, + "wires": [] + }, + { + "id": "264eece408043021", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "5d267acc10020091", + "3876d5cbd248592b" + ], + "x": 835, + "y": 1380, + "wires": [] + }, + { + "id": "3876d5cbd248592b", + "type": "link in", + "z": "e43a27722b508115", + "name": "OSCparameters", + "links": [ + "960912e90ba5b5bc", + "264eece408043021", + "b42e061fb1f1f3d7", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1400, + "wires": [ + [ + "5daca3ec47f8e7fc" + ] + ] + }, + { + "id": "50f73cee213ec05c", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "b4c843620c251c43", + "5d267acc10020091" + ], + "x": 835, + "y": 1340, + "wires": [] + }, + { + "id": "95578e54a9b61cba", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 250, + "y": 1540, + "wires": [ + [ + "d7a5693da7855da8" + ] + ] + }, + { + "id": "d7a5693da7855da8", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", + "outputs": 2, + "x": 390, + "y": 1540, + "wires": [ + [ + "2b02b97dd1614e52" + ], + [ + "183a629accb417b1" + ] + ] + }, + { + "id": "183a629accb417b1", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1580, + "wires": [ + [] + ] + }, + { + "id": "2b02b97dd1614e52", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1540, + "wires": [ + [ + "3e4c15d7b538f816" + ] + ] + }, + { + "id": "3bf622f344172721", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "SUBMIT", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 810, + "y": 1540, + "wires": [ + [ + "e431cb2b8d217cee" + ] + ] + }, + { + "id": "e431cb2b8d217cee", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", + "outputs": 1, + "x": 950, + "y": 1540, + "wires": [ + [ + "106874534890f229" + ] + ] + }, + { + "id": "a38d7fde5c73210f", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Register", + "group": "12b719cba49817c9", + "order": 6, + "width": 2, + "height": 1, + "passthru": false, + "label": "Register", + "tooltip": "testtesttest", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "Please enter your email address:", + "payloadType": "str", + "topic": "Requesting an OpenScanCloud Token", + "topicType": "str", + "x": 100, + "y": 1540, + "wires": [ + [ + "95578e54a9b61cba" + ] + ] + }, + { + "id": "106874534890f229", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 1090, + "y": 1540, + "wires": [ + [] + ] + }, + { + "id": "5daca3ec47f8e7fc", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", + "outputs": 1, + "x": 230, + "y": 1400, + "wires": [ + [ + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" + ] + ] + }, + { + "id": "f34de19d4cf810a9", + "type": "comment", + "z": "e43a27722b508115", + "name": "Motor", + "info": "", + "x": 90, + "y": 1740, + "wires": [] + }, + { + "id": "26c2b58e21f97475", + "type": "comment", + "z": "e43a27722b508115", + "name": "Camera", + "info": "", + "x": 90, + "y": 2500, + "wires": [] + }, + { + "id": "a8ec972bad47a9a8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Pinout", + "info": "", + "x": 90, + "y": 2960, + "wires": [] + }, + { + "id": "b03e8b51187e88eb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "Rotor_delay (ms)", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 16, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 450, + "y": 2100, + "wires": [ + [ + "11fd3363416433f9" + ] + ] + }, + { + "id": "6aae9d4fddf08cc0", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt delay", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 30, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 420, + "y": 2340, + "wires": [ + [ + "e50492d1e18f43c6" + ] + ] + }, + { + "id": "543e1690693acbeb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 18, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 420, + "y": 2140, + "wires": [ + [ + "e8b24efb0f30288e" + ] + ] + }, + { + "id": "9a56c087d941f1da", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 20, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "100", + "max": "5000", + "step": "100", + "className": "", + "x": 440, + "y": 2180, + "wires": [ + [ + "29f576be9e292232" + ] + ] + }, + { + "id": "dfdebe10dbf0e198", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotor_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 14, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 460, + "y": 2060, + "wires": [ + [ + "78e256083f59f66f" + ] + ] + }, + { + "id": "af8dfe78cbd0c301", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, + "width": 3, + "height": 1, + "name": "rotor Accramp", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2140, + "wires": [] + }, + { + "id": "ee4b8908a5b83880", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, + "width": 3, + "height": 1, + "name": "rotor_Steps per Rotation", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 810, + "y": 2180, + "wires": [] + }, + { + "id": "c4deaa38c1b0adbf", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, + "width": 3, + "height": 1, + "name": "rotor Acc", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2100, + "wires": [] + }, + { + "id": "baec873a95fff48a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, + "width": 3, + "height": 1, + "name": "rotor_delay", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 770, + "y": 2060, + "wires": [] + }, + { + "id": "355e89ab4e5484e4", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 26, + "width": 6, + "height": 1, + "name": "tt", + "label": "TURNTABLE", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 2300, + "wires": [] + }, + { + "id": "10687d331a732790", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 32, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 410, + "y": 2380, + "wires": [ + [ + "af88b9da72917d62" + ] + ] + }, + { + "id": "721b9680a3fa460e", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 34, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "500", + "step": "1", + "className": "", + "x": 430, + "y": 2420, + "wires": [ + [ + "b1b4678827d3a6dd" + ] + ] + }, + { + "id": "c6642c7470d3820c", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "tt_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 28, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 450, + "y": 2300, + "wires": [ + [ + "eef89545ec0f6aa8" + ] + ] + }, + { + "id": "18e5918748660109", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 33, + "width": 3, + "height": 1, + "name": "ttAccramp", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2420, + "wires": [] + }, + { + "id": "8e805244dc1899e8", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 27, + "width": 3, + "height": 1, + "name": "tt_steps per Rotation", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 800, + "y": 2300, + "wires": [] + }, + { + "id": "a09e5fbea861bfb1", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 31, + "width": 3, + "height": 1, + "name": "tt Acc", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 750, + "y": 2380, + "wires": [] + }, + { + "id": "7b06448b3b222011", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 29, + "width": 3, + "height": 1, + "name": "tt_delay", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 760, + "y": 2340, + "wires": [] + }, + { + "id": "0dfc86d90258f9bb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 22, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 430, + "y": 2220, + "wires": [ + [ + "c4b5a38c5c1df3d2" + ] + ] + }, + { + "id": "9319d7d4f34c6d22", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, + "width": 3, + "height": 1, + "name": "rotor_angle", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 770, + "y": 2220, + "wires": [] + }, + { + "id": "1610895f430b9aca", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 36, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 420, + "y": 2460, + "wires": [ + [ + "0f3367983bb8e159" + ] + ] + }, + { + "id": "96a9febc0928b6f0", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 35, + "width": 3, + "height": 1, + "name": "tt_angle", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2460, + "wires": [] + }, + { + "id": "e2c5ea8c16a5ea32", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, + "width": 6, + "height": 1, + "name": "rotor", + "label": "ROTOR", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 1820, + "wires": [] + }, + { + "id": "277037c4716d85bf", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 38, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 410, + "y": 2500, + "wires": [ + [ + "c9d2e31514def4fc" + ] + ] + }, + { + "id": "1361134e9847f003", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 24, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 420, + "y": 2260, + "wires": [ + [ + "523717b0f218a5fd" + ] + ] + }, + { + "id": "6b0d58943ecb8bb2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 37, + "width": 3, + "height": 1, + "name": "tt_dir", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2500, + "wires": [] + }, + { + "id": "08f93dd2aeedb391", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, + "width": 3, + "height": 1, + "name": "rotor_dir", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2260, + "wires": [] + }, + { + "id": "46b91bef44714366", + "type": "link in", + "z": "e43a27722b508115", + "name": "advanced settings", + "links": [ + "8750ad979e9ea246" + ], + "x": 95, + "y": 100, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "8750ad979e9ea246", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "46b91bef44714366" + ], + "x": 955, + "y": 480, + "wires": [] + }, + { + "id": "2522f888dc58972f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_before", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 430, + "y": 2600, + "wires": [ + [ + "5c752757090c49d2" + ] + ] + }, + { + "id": "30e8df3d616512d8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_gain", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "10", + "step": "0.1", + "className": "", + "x": 400, + "y": 2640, + "wires": [ + [ + "a1769f0277834f6d" + ] + ] + }, + { + "id": "d855d926df89d65b", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_contrast", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2760, + "wires": [ + [ + "1a8b0ba21b4f3005", + "654bc70a18820828" + ] + ] + }, + { + "id": "7617517dc8ba2859", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_saturation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2800, + "wires": [ + [ + "dc8fc962ff7d594b", + "e64feb03a791ca33" + ] + ] + }, + { + "id": "cbaa23c34e10fae1", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_jpeg_q", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 3, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "100", + "step": "1", + "className": "", + "x": 410, + "y": 2840, + "wires": [ + [ + "00e7836ccb3c4d0c" + ] + ] + }, + { + "id": "bbe443b039a14e21", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, + "width": 3, + "height": 1, + "name": "delay_before", + "label": "Delay before", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2600, + "wires": [] + }, + { + "id": "d320ed3d701e6cc2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, + "width": 3, + "height": 1, + "name": "gain", + "label": "Gain", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2640, + "wires": [] + }, + { + "id": "f5834dd4646c8af9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, + "width": 3, + "height": 1, + "name": "contrast", + "label": "Contrast", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2760, + "wires": [] + }, + { + "id": "ae9a4e19469813ef", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, + "width": 3, + "height": 1, + "name": "saturation", + "label": "Saturation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2800, + "wires": [] + }, + { + "id": "bd629d0d31233c8b", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 2, + "width": 3, + "height": 1, + "name": "jpegQ", + "label": "Jpeg Quality", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2840, + "wires": [] + }, + { + "id": "e89f61dbe6a6cffe", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ext", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 3, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3000, + "wires": [ + [ + "885bc559fafec5f2" + ] + ] + }, + { + "id": "ece38cb172a12d75", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 2, + "width": 4, + "height": 1, + "name": "ext", + "label": "External Camera", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3000, + "wires": [] + }, + { + "id": "70014da0b6ab6698", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3040, + "wires": [ + [ + "f70321c96bf81360" + ] + ] + }, + { + "id": "29634ea5f6d666df", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 4, + "width": 4, + "height": 1, + "name": "light1", + "label": "Light 1", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3040, + "wires": [] + }, + { + "id": "2544963852c6881a", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 7, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3080, + "wires": [ + [ + "95e1603bbd06a69d" + ] + ] + }, + { + "id": "27903533cd85a59e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 6, + "width": 4, + "height": 1, + "name": "light2", + "label": "Light 2", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3080, + "wires": [] + }, + { + "id": "a1394401246eb735", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotordir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 9, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3120, + "wires": [ + [ + "a8f92ea6bf394640" + ] + ] + }, + { + "id": "bc0aa4bacdfa94ea", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 8, + "width": 4, + "height": 1, + "name": "rotordir", + "label": "Rotor direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3120, + "wires": [] + }, + { + "id": "f15ca4518b5f223e", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotorstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 11, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3160, + "wires": [ + [ + "06397bb46b3bb541" + ] + ] + }, + { + "id": "0d2924b160e7e383", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 10, + "width": 4, + "height": 1, + "name": "rotorstep", + "label": "Rotor step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3160, + "wires": [] + }, + { + "id": "49900bb9047dd965", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotoren", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 13, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3200, + "wires": [ + [ + "687dcdc1ede11700" + ] + ] + }, + { + "id": "a4d743ca73ee1622", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 12, + "width": 4, + "height": 1, + "name": "rotoren", + "label": "Rotor enable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3200, + "wires": [] + }, + { + "id": "5a90224dc998b417", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttdir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 15, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3240, + "wires": [ + [ + "e220740c0d38ccb0" + ] + ] + }, + { + "id": "67dc1b544c4ddf9f", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 14, + "width": 4, + "height": 1, + "name": "ttdir", + "label": "Turntable direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3240, + "wires": [] + }, + { + "id": "d2364ab09627fe94", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 17, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3280, + "wires": [ + [ + "79d7e5a705ab813a" + ] + ] + }, + { + "id": "145b67ac40721ba6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 16, + "width": 4, + "height": 1, + "name": "ttstep", + "label": "Turntable step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3280, + "wires": [] + }, + { + "id": "eef25405472acfee", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 19, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3320, + "wires": [ + [ + "12d20f2274bcc511" + ] + ] + }, + { + "id": "35eb252a41413531", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 18, + "width": 4, + "height": 1, + "name": "endstop1", + "label": "Endstop Rotor", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3320, + "wires": [] + }, + { + "id": "74e455136b5ca5dd", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 21, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3360, + "wires": [ + [ + "a4a89668ce4c9f05" + ] + ] + }, + { + "id": "3a74f653800eb831", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 20, + "width": 4, + "height": 1, + "name": "endstop2", + "label": "Endstop Turntable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3360, + "wires": [] + }, + { + "id": "5fcef1cb2e9e4788", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "confirm", + "x": 680, + "y": 480, + "wires": [ + [ + "29745a36fc157f3f" + ] + ] + }, + { + "id": "f06a7bcad524e9f9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", + "outputs": 1, + "x": 530, + "y": 480, + "wires": [ + [ + "5fcef1cb2e9e4788" + ] + ] + }, + { + "id": "f455fb39039617ae", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_rotation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "270", + "step": "90", + "className": "", + "x": 410, + "y": 2880, + "wires": [ + [ + "3019576de193d9d6" + ] + ] + }, + { + "id": "fdfbc900fe424eb9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, + "width": 3, + "height": 1, + "name": "cam_rot", + "label": "Image Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2880, + "wires": [] + }, + { + "id": "c3699d6b9664ccca", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2060, + "wires": [ + [ + "dfdebe10dbf0e198" + ] + ] + }, + { + "id": "78e256083f59f66f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2060, + "wires": [ + [] + ] + }, + { + "id": "0f9141b401322374", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2180, + "wires": [ + [ + "9a56c087d941f1da" + ] + ] + }, + { + "id": "29f576be9e292232", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2180, + "wires": [ + [] + ] + }, + { + "id": "23e3099b34c4e475", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2220, + "wires": [ + [ + "0dfc86d90258f9bb" + ] + ] + }, + { + "id": "c4b5a38c5c1df3d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2220, + "wires": [ + [] + ] + }, + { + "id": "79a14162ac805fac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2260, + "wires": [ + [ + "1361134e9847f003" + ] + ] + }, + { + "id": "523717b0f218a5fd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2260, + "wires": [ + [] + ] + }, + { + "id": "f5cf780f3fa8997e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2100, + "wires": [ + [ + "b03e8b51187e88eb" + ] + ] + }, + { + "id": "11fd3363416433f9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2100, + "wires": [ + [] + ] + }, + { + "id": "02060b3f3b294563", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2140, + "wires": [ + [ + "543e1690693acbeb" + ] + ] + }, + { + "id": "e8b24efb0f30288e", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2140, + "wires": [ + [] + ] + }, + { + "id": "de1ad8b27b72a5ac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nsteps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", + "outputs": 1, + "noerr": 4, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2300, + "wires": [ + [ + "c6642c7470d3820c" + ] + ] + }, + { + "id": "ed4d587cb4feb064", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2420, + "wires": [ + [ + "721b9680a3fa460e" + ] + ] + }, + { + "id": "5b02160c33605ae7", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2460, + "wires": [ + [ + "1610895f430b9aca" + ] + ] + }, + { + "id": "304c135ec09801e3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2500, + "wires": [ + [ + "277037c4716d85bf" + ] + ] + }, + { + "id": "a91dcbe0f9a2416a", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2340, + "wires": [ + [ + "6aae9d4fddf08cc0" + ] + ] + }, + { + "id": "6b2eb1cb95e573f9", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2380, + "wires": [ + [ + "10687d331a732790" + ] + ] + }, + { + "id": "eef89545ec0f6aa8", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2300, + "wires": [ + [] + ] + }, + { + "id": "b1b4678827d3a6dd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2420, + "wires": [ + [] + ] + }, + { + "id": "0f3367983bb8e159", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2460, + "wires": [ + [] + ] + }, + { + "id": "c9d2e31514def4fc", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2500, + "wires": [ + [] + ] + }, + { + "id": "e50492d1e18f43c6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2340, + "wires": [ + [] + ] + }, + { + "id": "af88b9da72917d62", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2380, + "wires": [ + [] + ] + }, + { + "id": "43fe948b3e7234e2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2600, + "wires": [ + [ + "2522f888dc58972f" + ] + ] + }, + { + "id": "5c752757090c49d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2600, + "wires": [ + [] + ] + }, + { + "id": "435681b3f7625a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2640, + "wires": [ + [ + "30e8df3d616512d8" + ] + ] + }, + { + "id": "a1769f0277834f6d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2640, + "wires": [ + [] + ] + }, + { + "id": "1de07c7d285cbaf3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2760, + "wires": [ + [ + "d855d926df89d65b" + ] + ] + }, + { + "id": "1a8b0ba21b4f3005", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2760, + "wires": [ + [] + ] + }, + { + "id": "ebc9e283468eda31", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2800, + "wires": [ + [ + "7617517dc8ba2859" + ] + ] + }, + { + "id": "dc8fc962ff7d594b", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2800, + "wires": [ + [] + ] + }, + { + "id": "60d641613527c736", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2840, + "wires": [ + [ + "cbaa23c34e10fae1" + ] + ] + }, + { + "id": "00e7836ccb3c4d0c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2840, + "wires": [ + [] + ] + }, + { + "id": "7f24c0c34a88ba04", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2880, + "wires": [ + [ + "f455fb39039617ae" + ] + ] + }, + { + "id": "3019576de193d9d6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2880, + "wires": [ + [] + ] + }, + { + "id": "77bb7dc529d63a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3000, + "wires": [ + [ + "e89f61dbe6a6cffe" + ] + ] + }, + { + "id": "885bc559fafec5f2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3000, + "wires": [ + [] + ] + }, + { + "id": "cc6dabe017a9c8a8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3320, + "wires": [ + [ + "eef25405472acfee" + ] + ] + }, + { + "id": "12d20f2274bcc511", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3320, + "wires": [ + [] + ] + }, + { + "id": "dcb9fed8122759fd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3040, + "wires": [ + [ + "70014da0b6ab6698" + ] + ] + }, + { + "id": "f70321c96bf81360", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3040, + "wires": [ + [] + ] + }, + { + "id": "013d2057c2347a62", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3080, + "wires": [ + [ + "2544963852c6881a" + ] + ] + }, + { + "id": "95e1603bbd06a69d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3080, + "wires": [ + [] + ] + }, + { + "id": "f88bbf11d5aa9a14", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3120, + "wires": [ + [ + "a1394401246eb735" + ] + ] + }, + { + "id": "a8f92ea6bf394640", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3120, + "wires": [ + [] + ] + }, + { + "id": "301af70731e096e5", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3160, + "wires": [ + [ + "f15ca4518b5f223e" + ] + ] + }, + { + "id": "06397bb46b3bb541", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3160, + "wires": [ + [] + ] + }, + { + "id": "0456a9ec4c236c9e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3200, + "wires": [ + [ + "49900bb9047dd965" + ] + ] + }, + { + "id": "687dcdc1ede11700", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3200, + "wires": [ + [] + ] + }, + { + "id": "09d37ba08ec0f163", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3240, + "wires": [ + [ + "5a90224dc998b417" + ] + ] + }, + { + "id": "37d954a4cf7e87ea", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3280, + "wires": [ + [ + "d2364ab09627fe94" + ] + ] + }, + { + "id": "e220740c0d38ccb0", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3240, + "wires": [ + [] + ] + }, + { + "id": "79d7e5a705ab813a", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3280, + "wires": [ + [] + ] + }, + { + "id": "21dc963d967d9c99", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3360, + "wires": [ + [ + "74e455136b5ca5dd" + ] + ] + }, + { + "id": "a4a89668ce4c9f05", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3360, + "wires": [ + [] + ] + }, + { + "id": "22ef66b0e2058be2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 360, + "wires": [ + [ + "cb3437ec113e1b6f" + ] + ] + }, + { + "id": "9ce01c8ba97932c1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 400, + "wires": [ + [ + "60fd0adce1cfeb82" + ] + ] + }, + { + "id": "81356177176eebcf", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 480, + "wires": [ + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "b78346ca3ce70c68", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 320, + "wires": [ + [ + "f0d8dbcca76a1926" + ] + ] + }, + { + "id": "e95b86cbac1b03b9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "3e4c15d7b538f816", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 670, + "y": 1540, + "wires": [ + [ + "3bf622f344172721" + ] + ] + }, + { + "id": "0f0871baf322b6d0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1820, + "wires": [ + [ + "6ebd15c61a5ca891" + ] + ] + }, + { + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1820, + "wires": [ + [] + ] + }, + { + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, + "wires": [ + [ + "acd10a4c99ee8063" + ] + ] + }, + { + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, + "wires": [ + [ + "031d7697768d0e77" + ] + ] + }, + { + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, + "wires": [ + [ + "be1954dd71d2c94c" + ] + ] + }, + { + "id": "edb1c8fae8b65c82", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1860, + "wires": [ + [ + "3ad0f0f206e4a873" + ] + ] + }, + { + "id": "031d7697768d0e77", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1860, + "wires": [ + [] + ] + }, + { + "id": "462a8f3ca75fc3c8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1900, + "wires": [ + [ + "3b6d759ed5be647f" + ] + ] + }, + { + "id": "be1954dd71d2c94c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1900, + "wires": [ + [] + ] + }, + { + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, + "wires": [ + [ + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88" + ] + ] + }, + { + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, + "y": 940, + "wires": [ + [ + "ded3086945a6d4b5", + "6ea3cdab41f20f92" + ] + ] + }, + { + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, + "wires": [ + [ + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd" + ] + ] + }, + { + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2540, + "wires": [ + [ + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" + ] + ] + }, + { + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3000, + "wires": [ + [ + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8", + "21dc963d967d9c99" + ] + ] + }, + { + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 620, + "wires": [ + [ + "53e6681d7254d484" + ] + ] + }, + { + "id": "53e6681d7254d484", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 270, + "y": 620, + "wires": [ + [ + "c11e79cfa7bc10b7" + ] + ] + }, + { + "id": "c11e79cfa7bc10b7", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 620, + "wires": [ + [ + "307782d10c1acdaf" + ] + ] + }, + { + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 620, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "cca3300a8f0daf4d", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 750, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "654bc70a18820828", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_contrast?contrast=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2720, + "wires": [ + [] + ] + }, + { + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_saturation?saturation=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2680, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2560, + "wires": [ + [ + "e612073aded01a8f" + ] + ] + }, + { + "id": "0d92559980944ae3", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, + "width": 3, + "height": 1, + "name": "delay_after", + "label": "Delay after", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2560, + "wires": [] + }, + { + "id": "6281b2e6e081104d", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2560, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2560, + "wires": [ + [] + ] + }, + { + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 520, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 210, + "y": 980, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 220, + "y": 1020, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 240, + "y": 1060, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] + }, + { + "id": "a7d233f984009e2e", + "type": "function", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 440, + "y": 980, + "wires": [ + [ + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" + ] + ] + }, + { + "id": "65518f3d4e3095e5", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 1", + "links": [ + "200d4b9951b6e066" + ], + "x": 85, + "y": 980, + "wires": [ + [ + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" + ] + ] + }, + { + "id": "9b851aa999e86fd7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", + "outputs": 1, + "x": 670, + "y": 980, + "wires": [ + [ + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" + ] + ] + }, + { + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 870, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, + "wires": [] + }, + { + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", + "links": [ + "592ec13d8f8923a9" + ], + "x": 815, + "y": 1020, + "wires": [] + }, + { + "id": "1eef47e0074545a9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, + "wires": [ + [ + "c994c779e4bad800", + "36890eb99a2ca1cf" + ], + [] + ] + }, + { + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, + "wires": [ + [ + "1eef47e0074545a9" + ] + ] + }, + { + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", + "name": "", + "x": 670, + "y": 1020, + "wires": [] + }, + { + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, + "wires": [] + }, + { + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, + "wires": [ + [ + "85ad07b8f973bbe2" + ] + ] + }, + { + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "endstop_angle", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2020, + "wires": [] + }, + { + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, + "wires": [ + [] + ] + }, + { + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, + "wires": [ + [ + "6b7245c3dcb694c8" + ] + ] + }, + { + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, + "wires": [ + [ + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" + ] + ] + }, + { + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, + "wires": [ + [ + "253feafa5a2f8b1d" + ] + ] + }, + { + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, + "wires": [ + [] + ] + }, + { + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_enable_endstop", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 1980, + "wires": [ + [ + "69516440e3997111", + "f036424d79645761" + ] + ] + }, + { + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, + "wires": [ + [ + "eefed04c25e3e4d6" + ] + ] + }, + { + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, + "wires": [ + [ + "2aaf7c7f0f0c146f" + ] + ] + }, + { + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", + "outputs": 1, + "x": 660, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3560, + "wires": [ + [ + "d0a1a4947a1137ca" + ] + ] + }, + { + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 520, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] + }, + { + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, + "wires": [ + [] + ] + }, + { + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3640, + "wires": [ + [ + "b5aba11033c5f952" + ] + ] + }, + { + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, + { + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'stable'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, + "wires": [ + [ + "e23c514008cad1a1" + ] + ] + }, + { + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] + }, + { + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, + "wires": [ + [ + "4ce127c61c3c5966", + "beacc3dc5398fa79" + ] + ] + }, + { + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", + "outputs": 1, + "x": 290, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "beacc3dc5398fa79", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "e23c514008cad1a1", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 480, + "y": 140, + "wires": [] + }, + { + "id": "b0629875a30ae1d7", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", + "outputs": 2, + "x": 390, + "y": 540, + "wires": [ + [ + "1bbe2d769f42c313" + ], + [ + "fefe45404bdb19c4" + ] + ] + }, + { + "id": "c7b6d05a62172432", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Status:", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 210, + "y": 400, + "wires": [] + }, + { + "id": "fefe45404bdb19c4", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "check files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "outputs": 1, + "x": 550, + "y": 560, + "wires": [ + [ + "1bbe2d769f42c313", + "ae92a328af306ebb" + ] + ] + }, + { + "id": "d0104e0163745993", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 115, + "y": 440, + "wires": [ + [ + "ec30638407332e43", + "38cbf7965d1c1834", + "49f1ecb29a3f84f4" + ] + ] + }, + { + "id": "ec30638407332e43", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadS", + "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 480, + "wires": [ + [ + "2852023f3aa8db10" + ] + ] + }, + { + "id": "2852023f3aa8db10", + "type": "ui_dropdown", + "z": "a5557543ccff5889", + "name": "", + "label": "", + "tooltip": "", + "place": "Select option", + "group": "ddbd496e.93a288", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "stable", + "value": "stable", + "type": "str" + }, + { + "label": "beta", + "value": "beta", + "type": "str" + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" + } + ], + "payload": "", + "topic": "topic", + "topicType": "msg", + "className": "", + "x": 340, + "y": 480, + "wires": [ + [ + "1e10b387ee30c486" + ] + ] + }, + { + "id": "1e10b387ee30c486", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "274129c51b0b87ef", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 4, + "width": 4, + "height": 1, + "name": "", + "label": "Updatetype: ", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 610, + "y": 480, + "wires": [] + }, + { + "id": "51cd8c8643e6b46a", + "type": "ui_switch", + "z": "a5557543ccff5889", + "name": "", + "label": "Auto-check update availability", + "tooltip": "", + "group": "ddbd496e.93a288", + "order": 6, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 410, + "y": 440, + "wires": [ + [ + "1ab4c6b4b232a022" + ] + ] + }, + { + "id": "38cbf7965d1c1834", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 440, + "wires": [ + [ + "51cd8c8643e6b46a" + ] + ] + }, + { + "id": "1ab4c6b4b232a022", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 610, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "ae92a328af306ebb", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "NO", + "cancel": "YES", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 710, + "y": 560, + "wires": [ + [ + "2de63e8e3ae5fb0c", + "929281fef53e09f8" + ] + ] + }, + { + "id": "cbd0afc4aa7b302a", + "type": "link in", + "z": "a5557543ccff5889", + "name": "update status", + "links": [ + "1bbe2d769f42c313", + "42061b28cff81f99" + ], + "x": 115, + "y": 400, + "wires": [ + [ + "c7b6d05a62172432", + "c94623ddd9d95f78" + ] + ] + }, + { + "id": "1bbe2d769f42c313", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 665, + "y": 520, + "wires": [] + }, + { + "id": "7cf60615d93e696b", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 7, + "width": 6, + "height": 1, + "passthru": false, + "label": "Check Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 180, + "y": 560, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "2de63e8e3ae5fb0c", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "download files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "outputs": 1, + "x": 880, + "y": 560, + "wires": [ + [ + "42061b28cff81f99", + "fe3a855fee9e28c6" + ] + ] + }, + { + "id": "929281fef53e09f8", + "type": "function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 850, + "y": 520, + "wires": [ + [ + "42061b28cff81f99" + ] + ] + }, + { + "id": "42061b28cff81f99", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 995, + "y": 520, + "wires": [] + }, + { + "id": "49f1ecb29a3f84f4", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 520, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "fe3a855fee9e28c6", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "9bb0adbd716ce347", + "01c882fcc51b349c" + ], + "x": 995, + "y": 560, + "wires": [] + }, + { + "id": "5e7d5e4335d37794", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 95, + "y": 700, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "2bb5fe78e09fec8a", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", + "outputs": 1, + "x": 210, + "y": 700, + "wires": [ + [ + "dbc77052ac950624", + "d97c3068ef5fef96", + "73a3b828f862312b", + "901e31453b2bdff8", + "f983854748ee4763", + "5347c7c517f5e8c7", + "3a5016f7003cd72c", + "6d720c4a4ecd9475", + "6438b7d060a70d81" + ] + ] + }, + { + "id": "d97c3068ef5fef96", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "OS:", + "format": "{{msg.os}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 740, + "wires": [] + }, + { + "id": "73a3b828f862312b", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 8, + "width": 0, + "height": 0, + "name": "", + "label": "Flask:", + "format": "{{msg.flask}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 780, + "wires": [] + }, + { + "id": "dbc77052ac950624", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Device:", + "format": "{{msg.device}}", + "layout": "row-spread", + "className": "", + "x": 500, + "y": 700, + "wires": [] + }, + { + "id": "3f42560297fe6978", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "name": "Download LOG", + "order": 9, + "width": 6, + "height": 1, + "format": "\n
Download error log\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 180, + "y": 1060, + "wires": [ + [] + ] + }, + { + "id": "c94623ddd9d95f78", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", + "outputs": 1, + "x": 210, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "39a502b38837273d", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "1e7457ea9c2c5e09" + ], + "x": 245, + "y": 600, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "901e31453b2bdff8", + "type": "delay", + "z": "a5557543ccff5889", + "name": "", + "pauseType": "delay", + "timeout": "10", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 220, + "y": 740, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "f983854748ee4763", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "", + "format": "{{msg.osdate}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 820, + "wires": [] + }, + { + "id": "5347c7c517f5e8c7", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "CPU temp:", + "format": "{{msg.temp}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 860, + "wires": [] + }, + { + "id": "3a5016f7003cd72c", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "CPU memory:", + "format": "{{msg.cpu}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 900, + "wires": [] + }, + { + "id": "6d720c4a4ecd9475", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 6, + "width": 0, + "height": 0, + "name": "", + "label": "Swap memory:", + "format": "{{msg.swap}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 940, + "wires": [] + }, + { + "id": "6438b7d060a70d81", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 7, + "width": 0, + "height": 0, + "name": "", + "label": "Diskspace:", + "format": "{{msg.diskspace}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 980, + "wires": [] + }, + { + "id": "8d012912f302be85", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 8, + "width": 6, + "height": 1, + "passthru": false, + "label": "Show Details/Changelog", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 210, + "y": 640, + "wires": [ + [ + "5242607a723cc628" + ] + ] + }, + { + "id": "5242607a723cc628", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "Changelog", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "outputs": 1, + "x": 430, + "y": 640, + "wires": [ + [ + "573722197b15bf84" + ] + ] + }, + { + "id": "573722197b15bf84", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 640, + "wires": [ + [] + ] + } +] \ No newline at end of file diff --git a/update/mini/settings.js b/update/2024-11S/stable/settings.js similarity index 92% rename from update/mini/settings.js rename to update/2024-11S/stable/settings.js index 834f457..357b02b 100644 --- a/update/mini/settings.js +++ b/update/2024-11S/stable/settings.js @@ -1,5 +1,5 @@ /** - * Node-RED Settings created at Mon, 24 Jan 2022 08:17:31 GMT + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT * * It can contain any valid JavaScript code that will get run when Node-RED * is started. @@ -19,6 +19,7 @@ * - Node Settings * **/ +process.env.HOSTNAME = require('os').hostname(); module.exports = { @@ -54,7 +55,8 @@ module.exports = { * property can be used */ //userDir: '/home/nol/.node-red/', - userDir: '/home/pi/OpenScan/settings/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + /** Node-RED scans the `nodes` directory in the userDir to find local node files. * The following property can be used to specify an additional directory to scan. */ @@ -137,11 +139,12 @@ module.exports = { * - httpNodeCors * - httpNodeMiddleware * - httpStatic + * - httpStaticRoot ******************************************************************************/ /** the tcp port that the Node-RED web server is listening on */ -// uiPort: process.env.PORT || 1880, -uiPort: process.env.PORT || 80, + uiPort: process.env.PORT || 80, + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. * To listen on all IPv6 addresses, set uiHost to "::", * The following property can be used to listen on a specific interface. For @@ -164,8 +167,8 @@ uiPort: process.env.PORT || 80, * The following property can be used to specify a different root path. * If set to false, this is disabled. */ - //httpAdminRoot: '/admin', -httpAdminRoot: '/editor', + httpAdminRoot: '/editor', + /** The following property can be used to add a custom middleware function * in front of all admin http routes. For example, to set custom http * headers. It can be a single function or an array of middleware functions. @@ -218,9 +221,28 @@ httpAdminRoot: '/editor', /** When httpAdminRoot is used to move the UI to a different root path, the * following property can be used to identify a directory of static content * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot */ - //httpStatic: '/home/nol/node-red-static/', -httpStatic: '/home/pi/OpenScan/', + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + /******************************************************************************* * Runtime Settings * - lang @@ -348,9 +370,9 @@ httpStatic: '/home/pi/OpenScan/', }, codeEditor: { /** Select the text editor component used by the editor. - * Defaults to "ace", but can be set to "ace" or "monaco" + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired */ - lib: "ace", + lib: "monaco", options: { /** The follow options only apply if the editor is set to "monaco" * @@ -360,7 +382,7 @@ httpStatic: '/home/pi/OpenScan/', */ theme: "vs", /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. - * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html */ //fontSize: 14, //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", @@ -405,13 +427,14 @@ httpStatic: '/home/pi/OpenScan/', * will allow the `os` module to be accessed in a Function node using: * global.get("os") */ - functionGlobalContext: { - os:require('os'), - path:require('path'), - fs:require('fs'), - -}, - +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, /** The maximum number of messages nodes will buffer internally as part of their * operation. This applies across a range of nodes that operate on message sequences. * defaults to no limit. A value of 0 also means no limit is applied. @@ -425,8 +448,8 @@ httpStatic: '/home/pi/OpenScan/', * middleware:{function or array}, (req,res,next) - http middleware * ioMiddleware:{function or array}, (socket,next) - socket.io middleware */ - //ui: { path: "ui" }, -ui: { path: "" }, + ui: { path: "" }, + /** Colourise the console output of the debug node */ //debugUseColors: true, diff --git a/update/2024-11S/update.json b/update/2024-11S/update.json new file mode 100644 index 0000000..4fd7155 --- /dev/null +++ b/update/2024-11S/update.json @@ -0,0 +1,114 @@ +{ + "stable": { + "1": { + "src": "stable/fla.py", + "dst": "/home/pi/OpenScan/files/fla.py", + "filesize": 17869 + }, + "2": { + "src": "stable/OpenScan.py", + "dst": "/usr/lib/python3/dist-packages/OpenScan.py", + "filesize": 10249 + }, + "3": { + "src": "stable/config.txt", + "dst": "/boot/config.txt", + "filesize": 2162 + }, + "4": { + "src": "stable/flows.json", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", + "filesize": 327566 + }, + "5": { + "src": "stable/settings.js", + "dst": "/root/.node-red/settings.js", + "filesize": 21248 + } + }, + + "beta": { + "1": { + "src": "beta/fla.py", + "dst": "/home/pi/OpenScan/files/fla.py", + "filesize": 17869 + }, + "2": { + "src": "beta/OpenScan.py", + "dst": "/usr/lib/python3/dist-packages/OpenScan.py", + "filesize": 10249 + }, + "3": { + "src": "beta/config.txt", + "dst": "/boot/config.txt", + "filesize": 864 + }, + "4": { + "src": "beta/flows.json", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", + "filesize": 333492 + }, + "5": { + "src": "beta/settings.js", + "dst": "/root/.node-red/settings.js", + "filesize": 21248 + }, + "6": { + "src": "beta/OpenScanStatistics.py", + "dst": "/usr/lib/python3/dist-packages/OpenScanStatistics.py", + "filesize": 793 + }, + "7": { + "src": "beta/expand_root.sh", + "dst": "/home/pi/OpensScan/files/expand_root.sh", + "filesize": 170 + }, + "8": { + "src": "beta/startup.sh", + "dst": "/home/pi/OpensScan/files/startup.sh", + "filesize": 460 + } + }, + "meanwhile": { + "1": { + "src": "meanwhile/fla.py", + "dst": "/home/pi/OpenScan/files/fla.py", + "filesize": 17869 + }, + "2": { + "src": "meanwhile/OpenScan.py", + "dst": "/usr/lib/python3/dist-packages/OpenScan.py", + "filesize": 10249 + }, + "3": { + "src": "meanwhile/config.txt", + "dst": "/boot/config.txt", + "filesize": 864 + }, + "4": { + "src": "meanwhile/flows.json", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", + "filesize": 341336 + }, + "5": { + "src": "meanwhile/settings.js", + "dst": "/root/.node-red/settings.js", + "filesize": 21248 + }, + "6": { + "src": "meanwhile/OpenScanStatistics.py", + "dst": "/usr/lib/python3/dist-packages/OpenScanStatistics.py", + "filesize": 793 + }, + "7": { + "src": "meanwhile/expand_root.sh", + "dst": "/home/pi/OpensScan/files/expand_root.sh", + "filesize": 170 + }, + "8": { + "src": "meanwhile/startup.sh", + "dst": "/home/pi/OpensScan/files/startup.sh", + "filesize": 460 + } + } +} \ No newline at end of file diff --git a/update/2024-1o/beta/OpenScan.py b/update/2024-1o/beta/OpenScan.py new file mode 100644 index 0000000..cbce61c --- /dev/null +++ b/update/2024-1o/beta/OpenScan.py @@ -0,0 +1,317 @@ +basepath = '/home/pi/OpenScan/' +from os.path import isfile +import os + +def load_bool(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + if value == '1' or value == 'True' or value =='true': + value = True + else: + value = False + return value + +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + return True + +def load_str(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + return value + +def load_int(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = int(file.read().replace('\n','')) + return value + +def load_float(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = float(file.read().replace('\n','')) + return value + +def save(name, value): + filename = basepath+'settings/'+name + with open(filename, 'w+') as file: + file.write(str(value)) + return + +def OpenScanCloud(cmd, msg): + from requests import get + osc_user = 'openscan' + osc_pw = 'free' + osc_server = 'http://openscanfeedback.dnsuser.de:1334/' + + try: + r = get(osc_server + cmd, auth=(osc_user, osc_pw), params=msg) + except: + r = type('obj', (object,), {'status_code' : 404, 'text':None}) + return r + +def camera(cmd, msg = {}): + from requests import get + flask = 'http://127.0.0.1:1312/' + try: + r = get(flask + cmd, params=msg) + return r.status_code + except: + return 400 + +def motorrun(motor,angle,ES_enable=False,ES_start_state = True): + #motor can be "rotor", "tt" or "extra" + import RPi.GPIO as GPIO + from time import sleep + from math import cos + msg = {'cmd':'set'} + + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + + spr = load_int(motor + '_stepsperrotation') + dirpin = load_int('pin_' + motor + '_dir') + steppin = load_int('pin_' + motor +'_step') + ES_pin = load_int('pin_' + motor + '_endstop') + dir = load_int(motor + '_dir') + ramp = load_int(motor + '_accramp') + acc = load_float(motor + '_acc') + if motor != 'tt': + ES_pin = load_int('pin_' + motor + '_endstop') + else: + ES_pin = '33' + delay_init = load_float(motor + '_delay') + delay = delay_init + + step_count=int(angle*spr/360) * dir + GPIO.setup(dirpin, GPIO.OUT) + GPIO.setup(steppin, GPIO.OUT) + if motor != 'tt': + GPIO.setup(ES_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP) + + if (step_count>0): + GPIO.output(dirpin, GPIO.HIGH) + if(step_count<0): + GPIO.output(dirpin, GPIO.LOW) + step_count=-step_count + for x in range(step_count): + if ES_enable == True and GPIO.input(ES_pin) != ES_start_state and motor != 'tt': + i = 0 + while i <= 10: + if GPIO.input(ES_pin) == ES_start_state: + i = 11 + if i == 10: + return + i = i + 1 + + GPIO.output(steppin, GPIO.HIGH) + if x<=ramp and x<=step_count/2: + delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) + #delay=delay_init+(ramp-x)*(delay_init)/acc + elif step_count-x<=ramp and x>step_count/2: + delay = delay_init * (1-1/acc*cos(1*(ramp+x-step_count)/ramp)+1/acc) + #delay=delay_init+(ramp-step_count+x)*(delay_init)/acc + else: + delay = delay_init + sleep(delay) + GPIO.output(steppin, GPIO.LOW) + sleep(delay) + +def ringlight(number,state): + import RPi.GPIO as GPIO + msg = {'cmd':'set'} + pin = load_int('pin_ringlight' + str(number)) + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + GPIO.setup(pin, GPIO.OUT) + GPIO.output(pin, state) + +def take_photo(file): + from os import system + filepath = basepath + file + + model=load_str('model') + + shutter = str(load_int('cam_shutter')) + saturation = load_str('cam_saturation') + contrast = load_str('cam_contrast') + awbg_red = load_str('cam_awbg_red') + awbg_blue = load_str('cam_awbg_blue') + gain = load_str('cam_gain') + quality = load_int('cam_jpeg_quality') + filepath2 = '/home/pi/OpenScan/tmp/tmp.jpg' + #width = load_str('cam_resx') + #height = load_str('cam_resy') + timeout = load_str('cam_timeout') + cropx = load_int('cam_cropx')/200 + cropy = load_int('cam_cropy')/200 + rotation = load_int('cam_rotation') + AF = load_bool('cam_AFmode') + camera = load_str('camera') + + + if camera == 'imx519' and AF == True: + autofocus = ' --autofocus ' + else: + autofocus = '' + + if camera == "usb_webcam": + cmd = 'fswebcam -i 0 -r "1280x720" -F 5 --no-banner --jpeg 95 --save ' + filepath2 + else: + cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + ' >/dev/null 2>&1' + # cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + + system(cmd) + return cmd + +def get_points(samples=1): + from math import pi, sqrt, acos, atan2, cos, sin + + points = [] + phi = pi * (3. - sqrt(5.)) + for i in range(int(samples)): + y = 1 - (i / float(samples - 1)) * 2 + radius = sqrt(1 - y * y) + theta = phi * i + x = cos(theta) * radius + z = sin(theta) * radius + r=sqrt(x*x+y*y+z*z) + theta_neu=acos(z/r)*180/pi + phi_neu=atan2(y,x)*180/pi + points.append((theta_neu-90,phi_neu)) + points.sort() + return points + +def create_coordinates(angle_min, angle_max,point_count): + point_count_final=point_count + if angle_max < angle_min: + a = angle_min + angle_min = angle_max + angle_max = a + point_count=point_count*90/(angle_max-angle_min) + actual_points=0 + while actual_pointsangle_min and x20: + point_count=point_count+3 + else: + point_count=point_count+1 + return filtered + + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/2024-1o/beta/OpenScanStatistics.py b/update/2024-1o/beta/OpenScanStatistics.py new file mode 100755 index 0000000..8adf9dd --- /dev/null +++ b/update/2024-1o/beta/OpenScanStatistics.py @@ -0,0 +1,38 @@ +import json +import os +from datetime import datetime +from dataclasses import dataclass + +@dataclass +class ScanData: + arch: str + openscan_version: str + openscan_branch: str + shield: str + date_init: str # Format: YYYY-MM-DD HH:MM + date_end: str # Format: YYYY-MM-DD HH:MM + num_photos: int + done_photos: int + camera: str + stack_size: int + telegram_enabled: bool + delete_aborted: bool + endstop_enabled: bool + group_stack_photos: bool + aborted: bool + +class ScanStatistics: + def __init__(self, filename: str = "/home/pi/OpenScan/statistics") -> None: + self.filename: str = filename + + def write_statistics(self, scan_data: ScanData) -> None: + data: dict = scan_data.__dict__ # Convert dataclass to dictionary + + # Parse date_init to get year and month + date_object: datetime = datetime.strptime(scan_data.date_init, "%Y-%m-%d %H:%M") + record_filename: str = os.path.join(self.filename, f"statistics-{date_object.year}-{date_object.month:02d}.json") + + # Append the new data as a new line + with open(record_filename, "a") as json_file: + json.dump(data, json_file, separators=(',', ':'), indent=None) # Collapsed JSON + json_file.write('\n') # Add a newline after each entry \ No newline at end of file diff --git a/update/2024-1o/beta/config.txt b/update/2024-1o/beta/config.txt new file mode 100755 index 0000000..f601472 --- /dev/null +++ b/update/2024-1o/beta/config.txt @@ -0,0 +1,34 @@ +# For more options and information see +# http://rpf.io/configtxt +# Some settings may impact device functionality. See link above for details + +# Additional overlays and parameters are documented /boot/overlays/README + +# Automatically load overlays for detected cameras +# camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[pi4] +# Run as fast as firmware / board allows +arm_boost=1 +dtoverlay=imx519,cma-512 + +[all] +camera_auto_detect=0 +gpu_mem=256 +dtoverlay=imx519 \ No newline at end of file diff --git a/update/2024-1o/beta/fla.py b/update/2024-1o/beta/fla.py new file mode 100644 index 0000000..2a94655 --- /dev/null +++ b/update/2024-1o/beta/fla.py @@ -0,0 +1,536 @@ +from zipfile import ZipFile +from flask import Flask, request, redirect, send_file, send_from_directory +from flask_restx import Resource, Api, Namespace +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont +from time import sleep, time +from OpenScan import load_int, load_float, load_bool, ringlight, motorrun +from OpenScanSettings import get_openscan_settings, export_settings_to_file +import RPi.GPIO as GPIO +from math import sqrt +import os +import math +#from skimage import feature, color, transform +import numpy as np +from scipy import ndimage +import socket + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +app = Flask(__name__) +api = Api(app, version='1.0', title='OpenScan API', description='API for OpenScan') + +v1 = Namespace('v1', description='API v1') +# Create a namespace for system operations +system_ns = Namespace('system', description='System operations') +camera_ns = Namespace('camera', description='Camera operations') +motor_ns = Namespace('motor', description='Motor operations') + +api.add_namespace(v1, path='/v1') +api.add_namespace(system_ns, path='/v1/system') +api.add_namespace(camera_ns, path='/v1/camera') +api.add_namespace(motor_ns, path='/v1/motor') + +basedir = '/home/pi/OpenScan/' +timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + + +################################################################################################################### + + +@system_ns.route('/status') +class Status(Resource): + def get(self): + ''' + Get system status + ''' + import os + import json + from time import time + + if os.path.exists('/tmp/status.json'): + try: + with open('/tmp/status.json', 'r') as status_file: + status = json.load(status_file) + + elapsed_time = time() - status['start_time'] + estimated_total_time = (elapsed_time / status['current_photo']) * status['total_photos'] + time_remaining = max(0, estimated_total_time - elapsed_time) + + status.update({ + "status": "running", + "elapsed_time": int(elapsed_time), + "estimated_total_time": int(estimated_total_time), + "time_remaining": int(time_remaining) + }) + + return status, 200 + except Exception as e: + return {"error": f"Error reading status file: {str(e)}"}, 500 + else: + return {"status": "idle"}, 200 + +@system_ns.route('/get_settings') +class SendSettingsFile(Resource): + def get(self): + openscan_tmp_folder = '/home/pi/OpenScan/tmp2' + file_name = 'settings' + openscan_settings = get_openscan_settings() + export_settings_to_file(openscan_settings, openscan_tmp_folder + "/" + file_name + '.json') + + with ZipFile(openscan_tmp_folder + "/" + file_name + '.zip', 'w') as zip_object: + zip_object.write(openscan_tmp_folder + "/" + file_name + "json", zip_object.ZIP_DEFLATED) + if os.path.exists(openscan_tmp_folder + "/" + file_name + ".zip"): + print("ZIP file created") + else: + print("ZIP file not created") + return send_from_directory(openscan_tmp_folder, file_name + ".zip", as_attachment=True) + + +@system_ns.route('/shutdown') +class Shutdown(Resource): + @system_ns.doc(params={'token': 'Shutdown token for authentication'}) + def get(self): + '''Shutdown the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('shutdown -h now') + return {'message': 'Shutting down'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/reboot') +class Reboot(Resource): + @system_ns.doc(params={'token': 'Reboot token for authentication'}) + def get(self): + '''Reboot the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('reboot -h') + return {'message': 'Rebooting'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/ringlight') +class Ringlight(Resource): + @system_ns.doc(params={'state': 'Ringlight state (0 or 1)'}) + def get(self): + '''Set ringlight state''' + state = int(request.args.get('state')) + if state == 0: + ringlight(1, False) + ringlight(2, False) + else: + ringlight(1, True) + ringlight(2, True) + return {'message': f'Ringlight set to {state}'}, 200 + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) + + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') + + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wait 3-5s + return {'message': 'Auto focus triggered'}, 200 + +@motor_ns.route('/motor_run') +class MotorRun(Resource): + ''' + Run a motor + ''' + @motor_ns.doc(params={ + 'motor': 'Motor name (rotor, tt, extra)', + 'angle': 'Angle to rotate (integer)', + 'ES_enable': 'Enable endstop (optional, boolean)', + 'ES_start_state': 'Endstop start state (optional, boolean)' + }) + @motor_ns.response(400, 'Bad Request') + def get(self): + '''Run a motor''' + motor = request.args.get('motor') + if not motor: + return {'error': 'Motor parameter is required'}, 400 + if motor not in ['rotor', 'tt', 'extra']: + return {'error': 'Invalid motor name'}, 400 + + try: + angle = int(request.args.get('angle')) + except (TypeError, ValueError): + return {'error': 'Angle must be an integer'}, 400 + + ES_enable = request.args.get('ES_enable', 'false').lower() == 'true' + ES_start_state = request.args.get('ES_start_state', 'true').lower() == 'true' + + try: + motorrun(motor, angle, ES_enable, ES_start_state) + except Exception as e: + return {'error': f'Error running motor: {str(e)}'}, 500 + + return {'message': f'Motor {motor} run to {angle} degrees'}, 200 + + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) + diff --git a/update/2024-1o/beta/flows.json b/update/2024-1o/beta/flows.json new file mode 100644 index 0000000..7827fd0 --- /dev/null +++ b/update/2024-1o/beta/flows.json @@ -0,0 +1,9901 @@ +[ + { + "id": "e6f4d02efb300ea9", + "type": "tab", + "label": "Init", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "481edaf6db5a7a54", + "type": "tab", + "label": "Scan", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "80a3942785a26c29", + "type": "tab", + "label": "Files", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "e43a27722b508115", + "type": "tab", + "label": "Settings", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "a5557543ccff5889", + "type": "tab", + "label": "Update", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "87715429b0b1c9a3", + "type": "tab", + "label": "Statistics", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", + "type": "ui_tab", + "name": "Scan", + "icon": "dashboard", + "order": 3, + "disabled": false, + "hidden": false + }, + { + "id": "5c06cb6bcc371ee6", + "type": "ui_base", + "theme": { + "name": "theme-dark", + "lightTheme": { + "default": "#0094CE", + "baseColor": "#0094CE", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "darkTheme": { + "default": "#097479", + "baseColor": "#097479", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "customTheme": { + "name": "Untitled Theme 1", + "default": "#4B7930", + "baseColor": "#4B7930", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false + }, + "themeState": { + "base-color": { + "default": "#097479", + "value": "#097479", + "edited": false + }, + "page-titlebar-backgroundColor": { + "value": "#097479", + "edited": false + }, + "page-backgroundColor": { + "value": "#111111", + "edited": false + }, + "page-sidebar-backgroundColor": { + "value": "#333333", + "edited": false + }, + "group-textColor": { + "value": "#0eb8c0", + "edited": false + }, + "group-borderColor": { + "value": "#555555", + "edited": false + }, + "group-backgroundColor": { + "value": "#333333", + "edited": false + }, + "widget-textColor": { + "value": "#eeeeee", + "edited": false + }, + "widget-backgroundColor": { + "value": "#097479", + "edited": false + }, + "widget-borderColor": { + "value": "#333333", + "edited": false + }, + "base-font": { + "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + } + }, + "angularTheme": { + "primary": "indigo", + "accents": "blue", + "warn": "red", + "background": "grey", + "palette": "light" + } + }, + "site": { + "name": "OpenScan", + "hideToolbar": "false", + "allowSwipe": "false", + "lockMenu": "false", + "allowTempTheme": "true", + "dateFormat": "DD/MM/YYYY", + "sizes": { + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, + "cx": 6, + "cy": 6, + "px": 0, + "py": 0 + } + } + }, + { + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 9 + }, + { + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 8 + }, + { + "id": "b5fdd57b.15eda8", + "type": "ui_group", + "name": "Main", + "tab": "15a222ed.d70a7d", + "order": 1, + "disp": false, + "width": 13, + "collapse": false + }, + { + "id": "db43d646.2074c8", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", + "order": 2, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "15a222ed.d70a7d", + "type": "ui_tab", + "name": "Files&Cloud", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "365a30d0dfa83e95", + "type": "ui_group", + "name": "settings", + "tab": "e23b837a9f040895", + "order": 1, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "ac7409105cfecac6", + "type": "ui_group", + "name": "advanced", + "tab": "e23b837a9f040895", + "order": 3, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "729f9ea6e3513c9b", + "type": "ui_group", + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "b3150b13e34b1fe8", + "type": "ui_tab", + "name": "OpenScan", + "icon": "dashboard", + "order": 1, + "disabled": false, + "hidden": true + }, + { + "id": "ddbd496e.93a288", + "type": "ui_group", + "name": "Manage Updates", + "tab": "d25e08b4.5b27e8", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "3ce32450.e0cffc", + "type": "ui_group", + "name": "System & Stats", + "tab": "d25e08b4.5b27e8", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "d25e08b4.5b27e8", + "type": "ui_tab", + "name": "Update & Info", + "icon": "dashboard", + "order": 6, + "disabled": false, + "hidden": false + }, + { + "id": "4390b2ebcbbe104c", + "type": "ui_group", + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "8ab79a98e536e0d6", + "type": "ui_group", + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Rotor", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 5, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 1, + "width": 1, + "height": 1 + }, + { + "id": "33b6d7317d1524b8", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "aaf5b874c52a58aa", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, + "height": 1 + }, + { + "id": "f8d8740dcbf499fb", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 11, + "width": 1, + "height": 1 + }, + { + "id": "7ac0cb556740d159", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, + "height": 1 + }, + { + "id": "4de2414e29020c74", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "90223f7ddc082321", + "order": 2, + "width": 7, + "height": 1 + }, + { + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 + }, + { + "id": "ce21673092264c38", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, + "height": 1 + }, + { + "id": "3f7b77f8a1675d27", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "12b719cba49817c9", + "order": 7, + "width": 4, + "height": 1 + }, + { + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 8, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "ac59b8fb186de073", + "type": "ui_group", + "name": "Statistics", + "tab": "656b4eb8b15dab8f", + "order": 3, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "656b4eb8b15dab8f", + "type": "ui_tab", + "name": "Statistics", + "icon": "dashboard", + "order": 7, + "disabled": false, + "hidden": false + }, + { + "id": "0b244f698c7ac9a2", + "type": "ui_group", + "name": "Shield Type", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "f622137daacdfebe", + "type": "ui_group", + "name": "Group 3", + "tab": "b3150b13e34b1fe8", + "order": 3, + "disp": true, + "width": 6 + }, + { + "id": "38d121ea5b2bd77d", + "type": "ui_group", + "name": "Turntable", + "tab": "457102eadc9ddb6c", + "order": 9, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "dfb4a60f.d788f8", + "type": "ui_group", + "name": "Data Export", + "tab": "48418b79.0f5834", + "order": 1, + "disp": true, + "width": "12" + }, + { + "id": "48418b79.0f5834", + "type": "ui_tab", + "name": "Dashboard", + "icon": "dashboard", + "order": 2 + }, + { + "id": "c33a1024a72aa169", + "type": "ui_group", + "name": "Default", + "tab": "cc6c4310cf7b61cc", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "cc6c4310cf7b61cc", + "type": "ui_tab", + "name": "Home", + "icon": "dashboard", + "order": 10, + "disabled": false, + "hidden": false + }, + { + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 520, + "wires": [ + [ + "949bafced17d66d6" + ] + ] + }, + { + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "a1f0ed7d5a9d670e", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.1", + "topic": "", + "x": 110, + "y": 60, + "wires": [ + [ + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6", + "d81572486f15cd7a" + ] + ] + }, + { + "id": "544d20f02215011a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'openscan_branch':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 60, + "wires": [ + [ + "c77552216a8bb781" + ] + ] + }, + { + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 540, + "y": 60, + "wires": [ + [ + "960912e90ba5b5bc" + ] + ] + }, + { + "id": "960912e90ba5b5bc", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244", + "9b3e6a06c82a0f52", + "fbc5fc2e65311f8b" + ], + "x": 645, + "y": 60, + "wires": [] + }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "168d72a54504b327", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "5/0.1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "5", + "topic": "", + "payload": "", + "payloadType": "str", + "x": 100, + "y": 440, + "wires": [ + [ + "6c6ef2255a7d39e5" + ] + ] + }, + { + "id": "6c6ef2255a7d39e5", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "repeat 5s/0.1s", + "mode": "link", + "links": [ + "61990987acd0f263", + "2415272f42ce468c", + "6bf8344af427a6ba" + ], + "x": 205, + "y": 440, + "wires": [] + }, + { + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", + "outputs": 1, + "x": 270, + "y": 140, + "wires": [ + [ + "eb1a2387a1eeea76" + ] + ] + }, + { + "id": "b1e2491c952f84c9", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, + "wires": [ + [ + "200d4b9951b6e066" + ] + ] + }, + { + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "65518f3d4e3095e5", + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 800, + "y": 40, + "wires": [ + [ + "544d20f02215011a" + ] + ] + }, + { + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 470, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", + "outputs": 1, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 600, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 680, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 640, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 720, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "8955d11554f55e63", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "", + "order": 1, + "width": 6, + "height": 3, + "passthru": false, + "label": "Install Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "date", + "topic": "", + "topicType": "str", + "x": 120, + "y": 820, + "wires": [ + [ + "1e7457ea9c2c5e09" + ] + ] + }, + { + "id": "1e7457ea9c2c5e09", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "update", + "mode": "link", + "links": [ + "39a502b38837273d" + ], + "x": 245, + "y": 820, + "wires": [] + }, + { + "id": "245e4341d4fb611c", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 790, + "y": 540, + "wires": [ + [ + "627406f3611511dc" + ] + ] + }, + { + "id": "627406f3611511dc", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "write", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 930, + "y": 540, + "wires": [ + [ + "50eeb3e362f9027f" + ] + ] + }, + { + "id": "88b1bddde110298a", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 650, + "y": 540, + "wires": [ + [ + "245e4341d4fb611c" + ] + ] + }, + { + "id": "50eeb3e362f9027f", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "1dffb799fdf10cbc", + "2afb6a45c73fa244", + "2e9b29c70969cf01", + "2f4c0f98.dee2", + "3876d5cbd248592b", + "592ec13d8f8923a9", + "5e7d5e4335d37794", + "9b3e6a06c82a0f52", + "9fd259de91de1da1", + "b4c843620c251c43", + "cb40b9341bd22a28", + "d0104e0163745993", + "d1efcd5fa9d25785", + "da61581182b7299e", + "e5f38b4a07a5e278", + "fbc5fc2e65311f8b", + "fd0258418489839d" + ], + "x": 1015, + "y": 540, + "wires": [] + }, + { + "id": "4f3121f158f06a61", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", + "outputs": 1, + "x": 860, + "y": 580, + "wires": [ + [] + ] + }, + { + "id": "4a8a04b1e5dca8fe", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "run rotor till endstop", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 690, + "y": 580, + "wires": [ + [ + "4f3121f158f06a61" + ] + ] + }, + { + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n
    \n
  • speed improvement 2-3x
  • \n
  • currently tested on OpenScan Mini + IMX519 with RPi 4
  • \n
  • optimized toolpath
  • \n
  • more responsive user interface
  • \n
  • hotspot mode (when no wireless network available ssid: openscan pw: opensource
  • \n
  • preview features and sharpness
  • \n
  • partial background masking
  • \n
  • no more autofocus --> instead you can set a min and max focus distance
  • \n
\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 580, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "e548168473aa85d6", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 5, + "width": 0, + "height": 0, + "passthru": false, + "label": "Statistics", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "5", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 100, + "y": 760, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "d81572486f15cd7a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "loadl", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'openscan_version'\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.openscan_version = String(data);\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 360, + "wires": [ + [ + "0d8c6bc7887fb3c2", + "fa6db57803ae2b6d" + ] + ] + }, + { + "id": "fa6db57803ae2b6d", + "type": "debug", + "z": "e6f4d02efb300ea9", + "name": "debug 7", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 430, + "y": 400, + "wires": [] + }, + { + "id": "6a3d9acbe097a3d2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 120, + "wires": [ + [ + "cb6ebdabaaf7d0da" + ] + ] + }, + { + "id": "7ef6f1b5c67201fe", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "86f7d1b2d763f6e2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 160, + "wires": [ + [ + "c8a3fde5206ce1ae" + ] + ] + }, + { + "id": "fd799c931139764d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 240, + "wires": [ + [ + "87be854db758a9a6" + ] + ] + }, + { + "id": "d5140d455122c49a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 280, + "wires": [ + [ + "9daea4bd57f7a00e" + ] + ] + }, + { + "id": "194f3590dd4f6e3d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "2de69452e829d780", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", + "label": "", + "tooltip": "", + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, + "height": 1, + "passthru": true, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 320, + "y": 80, + "wires": [ + [ + "734ac3bff2df6837" + ] + ] + }, + { + "id": "97170908e1f4ac55", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 80, + "wires": [ + [ + "58e565fea35cb667" + ] + ] + }, + { + "id": "734ac3bff2df6837", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 55, + "y": 80, + "wires": [ + [ + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" + ] + ] + }, + { + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/v1/camera/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", + "outputs": 1, + "x": 510, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "c7f5808d753480d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 170, + "y": 200, + "wires": [ + [ + "11f41a6030578ef4" + ] + ] + }, + { + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 200, + "wires": [ + [ + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "855cbcadef1163c5", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 840, + "wires": [ + [ + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" + ] + ] + }, + { + "id": "1a443e20a973d2f1", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw true", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 630, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "d1b87196ae5373ed", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw false", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 430, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "03d92601c62b79d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "4s/0.5", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "Repeat", + "payload": "0.1", + "payloadType": "str", + "x": 100, + "y": 840, + "wires": [ + [ + "855cbcadef1163c5" + ] + ] + }, + { + "id": "41e6a4649b6afbfb", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Take Preview Shot", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/v1/camera/picam2_take_photo')\n\nreturn msg\n", + "outputs": 1, + "x": 450, + "y": 800, + "wires": [ + [ + "1a443e20a973d2f1", + "296636b7467fc745" + ] + ] + }, + { + "id": "85a268108250ba88", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", + "order": 1, + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 450, + "y": 840, + "wires": [ + [ + "417f653ca0dfdcfc", + "180476141c2a44ad" + ] + ] + }, + { + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, + "wires": [] + }, + { + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, + "wires": [ + [ + "e864254b18c23dd1" + ] + ] + }, + { + "id": "e864254b18c23dd1", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int\n\nif 'payload' not in msg:\n return\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'))\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'))\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'))\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'))\n\n", + "outputs": 1, + "x": 780, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "180476141c2a44ad", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 880, + "wires": [ + [ + "8cbdbfecbd12ef83" + ] + ] + }, + { + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", + "outputs": 1, + "x": 870, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", + "outputs": 1, + "x": 440, + "y": 720, + "wires": [ + [ + "923be3b2b25224b4" + ] + ] + }, + { + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "c8a3fde5206ce1ae", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 160, + "wires": [ + [ + "034ec9f59e50a361", + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "034ec9f59e50a361", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, + "wires": [ + [ + "194f3590dd4f6e3d" + ] + ] + }, + { + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, + "wires": [ + [ + "2de69452e829d780" + ] + ] + }, + { + "id": "cb6ebdabaaf7d0da", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 120, + "wires": [ + [ + "7ef6f1b5c67201fe" + ] + ] + }, + { + "id": "82ecd3cd971cb7ea", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, + "height": 1, + "name": "projectname", + "label": "Projectname", + "format": "", + "layout": "row-left", + "className": "", + "x": 530, + "y": 40, + "wires": [] + }, + { + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, + "wires": [ + [ + "06e1e19835a9816e" + ] + ] + }, + { + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, + "wires": [ + [ + "1fe18f3b0b52aabd" + ] + ] + }, + { + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "7dd287f40385922f", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "start ", + "group": "365a30d0dfa83e95", + "order": 10, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-play", + "payload": "", + "payloadType": "date", + "topic": "enabled", + "topicType": "str", + "x": 130, + "y": 1040, + "wires": [ + [ + "33d94a04b96a2de0", + "6d15f717d5a11002", + "9a6b30a0175a8ecd" + ] + ] + }, + { + "id": "579f2211199fd6ab", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "stop", + "group": "365a30d0dfa83e95", + "order": 12, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-stop", + "payload": "numberofphotos", + "payloadType": "global", + "topic": "", + "topicType": "str", + "x": 490, + "y": 1100, + "wires": [ + [ + "1787f08ed7070ddd", + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "1787f08ed7070ddd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "stop", + "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "outputs": 1, + "x": 630, + "y": 1100, + "wires": [ + [] + ] + }, + { + "id": "e9b13dfd9f8d3711", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 395, + "y": 1000, + "wires": [] + }, + { + "id": "9654deebb668e012", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "1s", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 290, + "y": 1140, + "wires": [ + [ + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "8367cfa0bf5bc5df", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine", + "links": [ + "200d4b9951b6e066", + "8689e938.dd9e38", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 45, + "y": 1040, + "wires": [ + [ + "7dd287f40385922f" + ] + ] + }, + { + "id": "fb13752beddee9f2", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 535, + "y": 1060, + "wires": [] + }, + { + "id": "33d94a04b96a2de0", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1100, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "c1c044f3c2139f68", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 1140, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "1daf9e3a5bd5ab48", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 430, + "y": 1040, + "wires": [ + [ + "fb13752beddee9f2" + ] + ] + }, + { + "id": "6d15f717d5a11002", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 1000, + "wires": [ + [ + "e9b13dfd9f8d3711" + ] + ] + }, + { + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "# The contents of this file are embedded in the OpenScan app (Node-RED)\nfrom OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom OpenScanStatistics import ScanStatistics, ScanData\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\nfrom datetime import datetime\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname, remove\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\nimport json\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\nstats = ScanStatistics()\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/v1/camera/picam2_switch_mode?mode=1')\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\narchitecture = load_str(\"architecture\")\nopenscan_version = load_str(\"openscan_version\")\nopenscan_branch = load_str(\"openscan_branch\")\ncamera_model = load_str(\"camera\")\nshield = load_str(\"shield_type\")\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\ndelete_aborted = load_bool('delete_aborted')\nrotate_tt_first = load_bool('rotate_tt_first')\nendstop_enable = load_bool('rotor_enable_endstop')\nif endstop_enable:\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True, False)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_current_timestamp():\n return datetime.now().strftime(\"%Y-%m-%d %H:%M\")\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/v1/camera/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/v1/camera/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n \n if rotate_tt_first:\n motorrun('tt',tt_angle)\n motorrun('rotor',rotor_angle)\n else:\n motorrun('rotor',rotor_angle)\n motorrun('tt',tt_angle)\n return\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/v1/camera/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\ncounter2 = 0\n\ndate_init = get_current_timestamp()\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\n\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n \n # Calculate time remaining and write status to /tmp/status as JSON\n elapsed_time = time() - starttime\n estimated_total_time = (elapsed_time / counter) * photocount * steps\n time_remaining = max(0, estimated_total_time - elapsed_time)\n \n status = {\n \"scan_name\": projectname,\n \"total_photos\": photocount,\n \"current_photo\": counter,\n \"stacksize\": steps,\n \"start_time\": int(starttime),\n }\n with open('/tmp/status.json', 'w') as status_file:\n json.dump(status, status_file)\n\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/v1/camera/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\ntry:\n remove('/tmp/status.json')\nexcept FileNotFoundError:\n pass # File doesn't exist, so no need to delete\nexcept Exception as e:\n print(f\"Error deleting /tmp/status.json: {e}\")\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\ndate_end = get_current_timestamp()\n\n\nif counter == photocount:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n aborted=False\nelse:\n aborted=True\n if delete_aborted:\n remove(zippath)\n else:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nscan_data = ScanData(\n arch=architecture,\n openscan_version=openscan_version,\n openscan_branch=openscan_branch,\n shield=shield,\n date_init=date_init,\n date_end=date_end,\n num_photos=photocount,\n done_photos=counter,\n camera=camera_model,\n stack_size=stacksize,\n telegram_enabled=telegram_enable,\n delete_aborted=delete_aborted,\n endstop_enabled=endstop_enable,\n group_stack_photos=group_stack_photos,\n aborted=aborted\n)\n\nstats.write_statistics(scan_data)\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, + "wires": [ + [ + "1daf9e3a5bd5ab48", + "795c85ad4f109567" + ] + ] + }, + { + "id": "afe47a9eaae6f67f", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, + "height": 1, + "name": "", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", + "className": "", + "x": 340, + "y": 40, + "wires": [] + }, + { + "id": "8608517d0567d63f", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 40, + "wires": [ + [ + "afe47a9eaae6f67f" + ] + ] + }, + { + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 55, + "y": 40, + "wires": [ + [ + "8608517d0567d63f" + ] + ] + }, + { + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, + "wires": [ + [ + "9774e7ad3b506354" + ] + ] + }, + { + "id": "9774e7ad3b506354", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 380, + "wires": [ + [ + "f0af909f3e739b22" + ] + ] + }, + { + "id": "39c744466a21735e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 40, + "wires": [ + [ + "fa181d22775c2ce6" + ] + ] + }, + { + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 80, + "wires": [ + [ + "c615034ea6b26174" + ] + ] + }, + { + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 480, + "wires": [ + [ + "237c2135cdad86ea" + ] + ] + }, + { + "id": "dd7fb8791d34c751", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 880, + "wires": [ + [ + "180476141c2a44ad" + ] + ] + }, + { + "id": "5baf89a2682265f7", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "enable led", + "links": [ + "eb1a2387a1eeea76" + ], + "x": 145, + "y": 880, + "wires": [ + [ + "dd7fb8791d34c751" + ] + ] + }, + { + "id": "6a26e8a7253d708c", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 40, + "wires": [ + [ + "39c744466a21735e" + ] + ] + }, + { + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, + "wires": [ + [ + "61aab497fa50898e" + ] + ] + }, + { + "id": "9fd259de91de1da1", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 735, + "y": 40, + "wires": [ + [ + "6a26e8a7253d708c", + "35ad7e55833836c1" + ] + ] + }, + { + "id": "fa181d22775c2ce6", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 40, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "c615034ea6b26174", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 80, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "ae5ee8787145906d", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import camera\ncamera('/v1/camera/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", + "outputs": 1, + "x": 1290, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "f0af909f3e739b22", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Features", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 420, + "wires": [ + [ + "710fc2dbb5ef0167" + ] + ] + }, + { + "id": "710fc2dbb5ef0167", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "d93c2b67bcf23b9a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 480, + "wires": [ + [ + "5e83b653850fa16e" + ] + ] + }, + { + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 95, + "y": 480, + "wires": [ + [ + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" + ] + ] + }, + { + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "c8b93b42c720b9cf", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", + "links": [ + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" + ], + "x": 85, + "y": 380, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 560, + "y": 960, + "wires": [] + }, + { + "id": "ea54fcc2.cfcc2", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "get dirs", + "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "outputs": 1, + "x": 480, + "y": 180, + "wires": [ + [ + "f3662f8c7d3d7a2d", + "01e4783e148c6698" + ] + ] + }, + { + "id": "2f4c0f98.dee2", + "type": "link in", + "z": "80a3942785a26c29", + "name": "filelist", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "a4f09e25.02569", + "ed35109311335099", + "fb13752beddee9f2" + ], + "x": 355, + "y": 220, + "wires": [ + [ + "ea54fcc2.cfcc2" + ] + ] + }, + { + "id": "952ce286.4ffd4", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 4, + "width": 6, + "height": 1, + "name": "Status", + "label": "Status", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 250, + "y": 60, + "wires": [] + }, + { + "id": "d4383424.7807c8", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "upload", + "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", + "outputs": 2, + "x": 530, + "y": 460, + "wires": [ + [ + "9a132ab1.b21658" + ], + [ + "3d16b3789632784d", + "9a132ab1.b21658" + ] + ] + }, + { + "id": "50710948.71c308", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "set", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 750, + "y": 180, + "wires": [ + [ + "ada1b6f7cccc9344", + "85839a17fb7b58b9" + ] + ] + }, + { + "id": "834046a4.647938", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 5, + "width": 6, + "height": 1, + "name": "Set", + "label": "Set:", + "format": "{{msg.payload.Name}}", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 220, + "wires": [] + }, + { + "id": "9a132ab1.b21658", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.true", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 780, + "y": 460, + "wires": [ + [ + "8689e938.dd9e38" + ] + ] + }, + { + "id": "3c67e97b.9d19a6", + "type": "function", + "z": "80a3942785a26c29", + "name": "enable", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 130, + "y": 340, + "wires": [ + [ + "7a93d1e18254685c", + "e434ef42bd6b92e8", + "d5d840183025d91b", + "ab9e90ab5a53a0dd", + "478994f671a3907d" + ] + ] + }, + { + "id": "bfc01f26.c32cf", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.false", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 500, + "wires": [ + [ + "f20f2dbc.0f123" + ] + ] + }, + { + "id": "b33d604c.5f1a6", + "type": "link in", + "z": "80a3942785a26c29", + "name": "enable cloud", + "links": [ + "4082b136.dae18", + "8689e938.dd9e38", + "bd75f33b8a57c522", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 35, + "y": 340, + "wires": [ + [ + "3c67e97b.9d19a6" + ] + ] + }, + { + "id": "f6bd1a04.470838", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "set", + "tot": "global" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 410, + "y": 460, + "wires": [ + [ + "d4383424.7807c8" + ] + ] + }, + { + "id": "4082b136.dae18", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "b33d604c.5f1a6", + "87574a42938afec4" + ], + "x": 715, + "y": 140, + "wires": [] + }, + { + "id": "f20f2dbc.0f123", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 515, + "y": 500, + "wires": [] + }, + { + "id": "8689e938.dd9e38", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 875, + "y": 460, + "wires": [] + }, + { + "id": "15de0ebb.616d61", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 380, + "wires": [ + [ + "a7d89487.ee8858" + ] + ] + }, + { + "id": "a7d89487.ee8858", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", + "outputs": 1, + "x": 690, + "y": 380, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "a4f09e25.02569", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2" + ], + "x": 775, + "y": 360, + "wires": [] + }, + { + "id": "7a93d1e18254685c", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "92c98e6ce7cd25f9" + ], + "x": 235, + "y": 500, + "wires": [] + }, + { + "id": "4d99c601c9881680", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "refresh", + "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", + "outputs": 2, + "x": 320, + "y": 180, + "wires": [ + [ + "ea54fcc2.cfcc2", + "b42e061fb1f1f3d7" + ], + [ + "6434e713f088012b" + ] + ] + }, + { + "id": "372e95797a3f2f3b", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "limit :)", + "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", + "outputs": 1, + "x": 90, + "y": 220, + "wires": [ + [ + "573edbfdb7500ddc" + ] + ] + }, + { + "id": "573edbfdb7500ddc", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 230, + "y": 220, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "dacb1f078b624e10", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 340, + "wires": [ + [ + "c8d65cc7c2ff7c36" + ] + ] + }, + { + "id": "92c98e6ce7cd25f9", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "7a93d1e18254685c", + "bd75f33b8a57c522" + ], + "x": 35, + "y": 180, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "3d16b3789632784d", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 770, + "y": 500, + "wires": [ + [] + ] + }, + { + "id": "6434e713f088012b", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 470, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "c8d65cc7c2ff7c36", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", + "outputs": 1, + "x": 690, + "y": 340, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "f4e9a4bd79b4221f", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 340, + "wires": [ + [ + "dacb1f078b624e10" + ] + ] + }, + { + "id": "2806bf08ea21216d", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 380, + "wires": [ + [ + "15de0ebb.616d61" + ] + ] + }, + { + "id": "61990987acd0f263", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 45, + "y": 60, + "wires": [ + [ + "51579603bce21e98" + ] + ] + }, + { + "id": "e8e488a6dd5d0b33", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "Download", + "order": 8, + "width": 3, + "height": 1, + "format": "\n
Download\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 880, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "0c387c0291d6c131", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 750, + "y": 260, + "wires": [ + [ + "e8e488a6dd5d0b33" + ] + ] + }, + { + "id": "e5f38b4a07a5e278", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 655, + "y": 220, + "wires": [ + [ + "834046a4.647938" + ] + ] + }, + { + "id": "e434ef42bd6b92e8", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "upload2", + "order": 7, + "width": 3, + "height": 1, + "format": "upload", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 460, + "wires": [ + [ + "f6bd1a04.470838" + ] + ] + }, + { + "id": "c46e10b9c201913e", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "refresh", + "order": 2, + "width": 4, + "height": 1, + "format": "refresh{{msg.text}}", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 160, + "y": 180, + "wires": [ + [ + "372e95797a3f2f3b", + "4d99c601c9881680" + ] + ] + }, + { + "id": "d5d840183025d91b", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del set", + "order": 11, + "width": 2, + "height": 1, + "format": "delete set", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 380, + "wires": [ + [ + "2806bf08ea21216d" + ] + ] + }, + { + "id": "ab9e90ab5a53a0dd", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del ", + "order": 10, + "width": 2, + "height": 1, + "format": "delete all", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 340, + "wires": [ + [ + "f4e9a4bd79b4221f" + ] + ] + }, + { + "id": "478994f671a3907d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "combine", + "order": 9, + "width": 2, + "height": 1, + "format": "combine", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 540, + "wires": [ + [ + "51bfd0fb7b1d292e" + ] + ] + }, + { + "id": "189c1eed09624a7b", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 580, + "wires": [ + [ + "1493398979a63775" + ] + ] + }, + { + "id": "51bfd0fb7b1d292e", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 420, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "da325be8e74179be", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", + "outputs": 1, + "x": 560, + "y": 580, + "wires": [ + [ + "ed35109311335099" + ] + ] + }, + { + "id": "ed35109311335099", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "2f4c0f98.dee2" + ], + "x": 655, + "y": 580, + "wires": [] + }, + { + "id": "1493398979a63775", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Combine", + "x": 420, + "y": 580, + "wires": [ + [ + "da325be8e74179be" + ] + ] + }, + { + "id": "ada1b6f7cccc9344", + "type": "link out", + "z": "80a3942785a26c29", + "name": "combine", + "mode": "link", + "links": [ + "6dd356510c446cf4" + ], + "x": 835, + "y": 180, + "wires": [] + }, + { + "id": "6dd356510c446cf4", + "type": "link in", + "z": "80a3942785a26c29", + "name": "combine", + "links": [ + "ada1b6f7cccc9344" + ], + "x": 175, + "y": 580, + "wires": [ + [ + "189c1eed09624a7b" + ] + ] + }, + { + "id": "b42e061fb1f1f3d7", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "397ab7f44b893c89", + "3876d5cbd248592b" + ], + "x": 435, + "y": 140, + "wires": [] + }, + { + "id": "b99505440832439f", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "diskspace", + "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", + "outputs": 1, + "x": 800, + "y": 100, + "wires": [ + [ + "92047434f8e9f927" + ] + ] + }, + { + "id": "92047434f8e9f927", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 950, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "f3662f8c7d3d7a2d", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "minute", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 650, + "y": 100, + "wires": [ + [ + "b99505440832439f" + ] + ] + }, + { + "id": "51579603bce21e98", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "read", + "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", + "outputs": 1, + "x": 130, + "y": 60, + "wires": [ + [ + "952ce286.4ffd4" + ] + ] + }, + { + "id": "9a5baae623355f9d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "preview", + "order": 6, + "width": 6, + "height": 6, + "format": "
\n\n\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1020, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "85839a17fb7b58b9", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "preview", + "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", + "outputs": 1, + "x": 880, + "y": 220, + "wires": [ + [ + "9a5baae623355f9d" + ] + ] + }, + { + "id": "01e4783e148c6698", + "type": "ui_table", + "z": "80a3942785a26c29", + "group": "b5fdd57b.15eda8", + "name": "", + "order": 1, + "width": 13, + "height": 7, + "columns": [ + { + "field": "Date", + "title": "Date", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Name", + "title": "Name", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Photos", + "title": "Photos", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Duration", + "title": "ΔT", + "width": "60", + "align": "left", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Size", + "title": "Size", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Status", + "title": "Status", + "width": "140", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + } + ], + "outputs": 1, + "cts": true, + "x": 610, + "y": 180, + "wires": [ + [ + "4082b136.dae18", + "50710948.71c308", + "834046a4.647938", + "0c387c0291d6c131" + ] + ] + }, + { + "id": "cb3437ec113e1b6f", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "SSH", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 3, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 390, + "y": 360, + "wires": [ + [ + "c24f61b87e3226dd" + ] + ] + }, + { + "id": "60fd0adce1cfeb82", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Samba", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "test2", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 400, + "wires": [ + [ + "441d3ef525e901da" + ] + ] + }, + { + "id": "c24f61b87e3226dd", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "ssh", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", + "outputs": 1, + "x": 530, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "c013e836e759a085", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "4390b2ebcbbe104c", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "label": "Terms Of Use", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 120, + "y": 320, + "wires": [ + [ + "b78346ca3ce70c68" + ] + ] + }, + { + "id": "f0d8dbcca76a1926", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "Agree", + "cancel": "Disagree", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 410, + "y": 320, + "wires": [ + [ + "e95b86cbac1b03b9" + ] + ] + }, + { + "id": "34374044c0030625", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "General", + "group": "4390b2ebcbbe104c", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

General Settings

Terms Of Use

In order to use the OpenScanCloud, please read the terms of use as files will be transmitted from your device to the OpenScan Servers.

SSH

SSH can be used to access the Raspberry Pi and modify core files of the operating system. Please deactivate, if you do not want to use this feature.

If you want to use it, the default user is pi, password: raspberry. Please change the password immediately. 

Samba

Samba s a network local file sharing server, which allows accessing the Raspberry Pi's file system through the explorer (and other programs like FileZilla). You can use it to transfer custom photo sets to the device in order to use the OpenScanCloud. Therefore, you need to transfer the zip file containing your photos to the following folder /OpenScan/scans/

You can access the Raspberry Pis file system by inserting the following line into your Windows explorer: 

\\\\OpenScan/PiShare/OpenScan/scans/

username: pi, password: raspberry

Please deactivate the local file sharing if you do not intend to use it

Advanced Settings

Enable a ton of additional settings, which should be changed only if you know what you are doing ;)

Model

Device model you are using: OpenScan Mini or OpenScan Classic. Setting the device affects the settings of the motor (gear ratio, acceleration, speed). You can change those values manually in the advanced settings.

Camera

A wide range of camera modules is supported (Pi camera v1.3, v2.1, HQ, Arducam IMX519, IMX290, IMX378, OV9281). If you encounter any issues with those models, please check the orientation of the camera ribbon cable and its connectors.

DSLR (gphoto) - connect a wide range of DSLR cameras to the device through USB. See GPhoto for a full list of supported devices.

External camera - triggering any camera through an isolated GPIO signal on the front side of the pi shield.

Shutdown/Reboot

Always use the shutdown button before you power off your Raspberry Pi.

Restore Default Settings

In case you want to restore the default settings

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "b2b6bf23c9989133", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Pinout", + "group": "70d0be671bf03ca7", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Pinout

ONLY CHANGE THE PINOUT IF YOU ARE ABSOLUTELY SURE! CHANGES CAN DAMAGE THE RASPBERRY PI AND ANY PERIPHERALS!


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "441d3ef525e901da", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "smb", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", + "outputs": 1, + "x": 530, + "y": 400, + "wires": [ + [] + ] + }, + { + "id": "3256bab150113a48", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Motor", + "group": "7a3279eea439bcdd", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Motor Settings

Turntable Mode

Activate turntable mode in order to deactivate the rotor. The routine will only move the turntable and take a given number of photos.

Rotor - Start Angle, Min and Max Angle

Since this version of OpenScan does not have an endstop (yet), it is necessary to tell the device its position when the routine is being started. 0° corresponds to the horizontal (natural) orientation.

After that, the device will equally space the image positions between angle min and angle max.

Rotor/Turntable

Steps per rotation -  defines the number of steps it takes to move the axis 360°. It is defined by A*B*C, where A is the number of steps for one revolution of the given stepper motor (normally 200), B is the microstepping used (normally 16), and C the gear ratio (1 for the turntable and 15 or 5,33 for the OpenScan Mini and Classic respectively)

Delay - time in microseconds between each step of the motor. Lower this value if the movement is too fast

Acceleration - a factor defining how fast the delay time between each step is being changed during acceleration and deceleration phases. Lower this value in order to make the movement smoother.

Acceleration ramp - the number of steps allowed for the acceleration processes. Increase this value, if you want smoother movement.

Manual Angle - Defines the degree value for the manual movement through the arrow buttons in the scan menu

Direction - If needed, reverse the movement (in case the arrow buttons and movement do not correspond). Alternatively, you can flip the motor cable 180° (BUT MAKE SURE TO POWER OFF THE DEVICE!)


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 140, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "7a186669a17daa71", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "camera", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Camera Settings

Jpeg quality

Value in percent, which usually does not need to be changed.

Downscale Preview

The preview image has to be scaled down depending on your network speed. If you want to have a higher quality preview image, you can increase this value, which defines the maximal width/height value. If the value is too high, the preview window might not update

Image Rotation

Change the image rotation, if needed.

Timeout

Defines the time in seconds, when the libcamera command (used for the camera modules) will timeout. Increase this value, if the camera does not get triggered in each position.

Delay Before/After

A fixed delay in seconds before and/or after a photo is taken. Increase this value when the photos have visual motion blur.

AWBG, Gain, Contrast, Saturation

Under most circumstances, you do not need to touch these values.

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 420, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "edac7dd292e7e486", + "type": "comment", + "z": "e43a27722b508115", + "name": "General Settings", + "info": "", + "x": 120, + "y": 280, + "wires": [] + }, + { + "id": "161b52034e578ee2", + "type": "comment", + "z": "e43a27722b508115", + "name": "Network", + "info": "", + "x": 100, + "y": 720, + "wires": [] + }, + { + "id": "f6d6cc35679ede63", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "more sets", + "label": "Advanced Settings", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 480, + "wires": [ + [ + "f06a7bcad524e9f9" + ] + ] + }, + { + "id": "29745a36fc157f3f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "more sets", + "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", + "outputs": 2, + "x": 820, + "y": 480, + "wires": [ + [ + "8750ad979e9ea246" + ], + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "bf23328f9fb11b22", + "type": "ui_ui_control", + "z": "e43a27722b508115", + "name": "change visibility", + "events": "all", + "x": 600, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "b37be1d222bc70c9", + "type": "inject", + "z": "e43a27722b508115", + "name": "1s_repeater", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "1", + "crontab": "", + "once": true, + "onceDelay": "2", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 150, + "y": 60, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "89eedf29b404f750", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, + "wires": [ + [ + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" + ] + ] + }, + { + "id": "2050de5d9e02f69f", + "type": "comment", + "z": "e43a27722b508115", + "name": "Info Texts", + "info": "", + "x": 100, + "y": 140, + "wires": [] + }, + { + "id": "ded3086945a6d4b5", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "check ip address", + "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", + "outputs": 1, + "x": 250, + "y": 940, + "wires": [ + [ + "3cfe464506f46ecd" + ] + ] + }, + { + "id": "3cfe464506f46ecd", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Your local IP:", + "format": "{{msg.ip}}", + "layout": "row-spread", + "className": "", + "x": 430, + "y": 940, + "wires": [] + }, + { + "id": "bd206ad109831e6a", + "type": "comment", + "z": "e43a27722b508115", + "name": "OpenScanCloud", + "info": "", + "x": 120, + "y": 1260, + "wires": [] + }, + { + "id": "b70a9a665c1e4d36", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Cloud-settings", + "group": "12b719cba49817c9", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

OpenScanCloud

OpenScanCloud is a free/donation-based cloud processing service, which will convert your photos into 3d models using latest photogrammetry technology. Feel free to support the project with a small donation at BuyMeACoffee.

The only requirement to use this service is a one-time, free-of-charge registration (which is solely an anti-spam measure). By filling out the registration form, you will receive an individual access token.

Register

In order to use the OpenScanCloud, you will have to enter your name and email. It might take 1-3 days to create the access token, which will be sent to your mail address. Please check your spam folder.

Enter Token

Please enter your individual token here in order to activate the cloud functionality. The token will be verified immediately. In case of any problems, please contact cloud@openscan.eu

Token

A shorted version of your token will be displayed here. Please include a copy of this shorted token in any support requests cloud@openscan.eu

Credit (GB)

Each token comes with a given amount of 'credit' which is another measure against spam. The given number in Gigabyte indicates the amount of data, that you can process on the servers. 

IMPORTANT: The credit can be increased at any time by sending a (nice) mail to cloud@openscan.eu

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 260, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "c9f0566601a3e130", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Number of Photos:", + "format": "{{msg.limit_photos}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 1400, + "wires": [] + }, + { + "id": "9bd86d27ea499a2a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Filesize (GB):", + "format": "{{msg.limit_filesize}}", + "layout": "row-spread", + "className": "", + "x": 390, + "y": 1440, + "wires": [] + }, + { + "id": "2c37f7030810d234", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Credit (GB):", + "format": "{{msg.credit}}", + "layout": "row-spread", + "className": "", + "x": 370, + "y": 1480, + "wires": [] + }, + { + "id": "f40286c18afd4501", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "save", + "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", + "outputs": 2, + "x": 750, + "y": 1340, + "wires": [ + [ + "455a5266017ea121", + "50f73cee213ec05c" + ], + [ + "264eece408043021" + ] + ] + }, + { + "id": "455a5266017ea121", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 890, + "y": 1300, + "wires": [ + [] + ] + }, + { + "id": "c368df68593bc2bf", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Token", + "tooltip": "", + "group": "12b719cba49817c9", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 350, + "y": 1360, + "wires": [ + [ + "18fd1afa768187b3" + ] + ] + }, + { + "id": "18fd1afa768187b3", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "Save?", + "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", + "outputs": 2, + "x": 470, + "y": 1360, + "wires": [ + [ + "418aea2ec65573a0" + ], + [ + "9792c89c5f4429f9" + ] + ] + }, + { + "id": "f90a98899b7a71d0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "text", + "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", + "outputs": 1, + "x": 230, + "y": 1360, + "wires": [ + [ + "c368df68593bc2bf" + ] + ] + }, + { + "id": "b4c843620c251c43", + "type": "link in", + "z": "e43a27722b508115", + "name": "token", + "links": [ + "960912e90ba5b5bc", + "50f73cee213ec05c", + "9792c89c5f4429f9", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1360, + "wires": [ + [ + "f90a98899b7a71d0" + ] + ] + }, + { + "id": "418aea2ec65573a0", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 1340, + "wires": [ + [ + "f40286c18afd4501" + ] + ] + }, + { + "id": "9792c89c5f4429f9", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "b4c843620c251c43" + ], + "x": 555, + "y": 1380, + "wires": [] + }, + { + "id": "264eece408043021", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "5d267acc10020091", + "3876d5cbd248592b" + ], + "x": 835, + "y": 1380, + "wires": [] + }, + { + "id": "3876d5cbd248592b", + "type": "link in", + "z": "e43a27722b508115", + "name": "OSCparameters", + "links": [ + "960912e90ba5b5bc", + "264eece408043021", + "b42e061fb1f1f3d7", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1400, + "wires": [ + [ + "5daca3ec47f8e7fc" + ] + ] + }, + { + "id": "50f73cee213ec05c", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "b4c843620c251c43", + "5d267acc10020091" + ], + "x": 835, + "y": 1340, + "wires": [] + }, + { + "id": "95578e54a9b61cba", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 250, + "y": 1540, + "wires": [ + [ + "d7a5693da7855da8" + ] + ] + }, + { + "id": "d7a5693da7855da8", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", + "outputs": 2, + "x": 390, + "y": 1540, + "wires": [ + [ + "2b02b97dd1614e52" + ], + [ + "183a629accb417b1" + ] + ] + }, + { + "id": "183a629accb417b1", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1580, + "wires": [ + [] + ] + }, + { + "id": "2b02b97dd1614e52", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1540, + "wires": [ + [ + "3e4c15d7b538f816" + ] + ] + }, + { + "id": "3bf622f344172721", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "SUBMIT", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 810, + "y": 1540, + "wires": [ + [ + "e431cb2b8d217cee" + ] + ] + }, + { + "id": "e431cb2b8d217cee", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", + "outputs": 1, + "x": 950, + "y": 1540, + "wires": [ + [ + "106874534890f229" + ] + ] + }, + { + "id": "a38d7fde5c73210f", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Register", + "group": "12b719cba49817c9", + "order": 6, + "width": 2, + "height": 1, + "passthru": false, + "label": "Register", + "tooltip": "testtesttest", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "Please enter your email address:", + "payloadType": "str", + "topic": "Requesting an OpenScanCloud Token", + "topicType": "str", + "x": 100, + "y": 1540, + "wires": [ + [ + "95578e54a9b61cba" + ] + ] + }, + { + "id": "106874534890f229", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 1090, + "y": 1540, + "wires": [ + [] + ] + }, + { + "id": "5daca3ec47f8e7fc", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", + "outputs": 1, + "x": 230, + "y": 1400, + "wires": [ + [ + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" + ] + ] + }, + { + "id": "f34de19d4cf810a9", + "type": "comment", + "z": "e43a27722b508115", + "name": "Motor", + "info": "", + "x": 90, + "y": 1740, + "wires": [] + }, + { + "id": "26c2b58e21f97475", + "type": "comment", + "z": "e43a27722b508115", + "name": "Camera", + "info": "", + "x": 90, + "y": 2500, + "wires": [] + }, + { + "id": "a8ec972bad47a9a8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Pinout", + "info": "", + "x": 90, + "y": 2960, + "wires": [] + }, + { + "id": "b03e8b51187e88eb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "Rotor_delay (ms)", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 16, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 450, + "y": 2100, + "wires": [ + [ + "11fd3363416433f9" + ] + ] + }, + { + "id": "6aae9d4fddf08cc0", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt delay", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 420, + "y": 2340, + "wires": [ + [ + "e50492d1e18f43c6" + ] + ] + }, + { + "id": "543e1690693acbeb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 18, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 420, + "y": 2140, + "wires": [ + [ + "e8b24efb0f30288e" + ] + ] + }, + { + "id": "9a56c087d941f1da", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 20, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "100", + "max": "5000", + "step": "100", + "className": "", + "x": 440, + "y": 2180, + "wires": [ + [ + "29f576be9e292232" + ] + ] + }, + { + "id": "dfdebe10dbf0e198", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotor_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 14, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 460, + "y": 2060, + "wires": [ + [ + "78e256083f59f66f" + ] + ] + }, + { + "id": "af8dfe78cbd0c301", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, + "width": 3, + "height": 1, + "name": "rotor_acc_label", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2140, + "wires": [] + }, + { + "id": "ee4b8908a5b83880", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, + "width": 3, + "height": 1, + "name": "rotor_accramp_label", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 800, + "y": 2180, + "wires": [] + }, + { + "id": "c4deaa38c1b0adbf", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, + "width": 3, + "height": 1, + "name": "rotor_delay_label", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 790, + "y": 2100, + "wires": [] + }, + { + "id": "baec873a95fff48a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, + "width": 3, + "height": 1, + "name": "rotor_steps_rotation_label", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 810, + "y": 2060, + "wires": [] + }, + { + "id": "355e89ab4e5484e4", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 1, + "width": 6, + "height": 1, + "name": "tt", + "label": "TURNTABLE", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 2300, + "wires": [] + }, + { + "id": "10687d331a732790", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_acc", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 410, + "y": 2380, + "wires": [ + [ + "af88b9da72917d62" + ] + ] + }, + { + "id": "721b9680a3fa460e", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_accramp", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "500", + "step": "1", + "className": "", + "x": 430, + "y": 2420, + "wires": [ + [ + "b1b4678827d3a6dd" + ] + ] + }, + { + "id": "c6642c7470d3820c", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "tt_stepsperrotation", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 450, + "y": 2300, + "wires": [ + [ + "eef89545ec0f6aa8" + ] + ] + }, + { + "id": "18e5918748660109", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 10, + "width": 3, + "height": 1, + "name": "tt_accramp_label", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2420, + "wires": [] + }, + { + "id": "8e805244dc1899e8", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 4, + "width": 3, + "height": 1, + "name": "tt_stepsperrotation_label", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 810, + "y": 2300, + "wires": [] + }, + { + "id": "a09e5fbea861bfb1", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 8, + "width": 3, + "height": 1, + "name": "tt_acc_label", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 770, + "y": 2380, + "wires": [] + }, + { + "id": "7b06448b3b222011", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 6, + "width": 3, + "height": 1, + "name": "tt_delay_label", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2340, + "wires": [] + }, + { + "id": "0dfc86d90258f9bb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 22, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 430, + "y": 2220, + "wires": [ + [ + "c4b5a38c5c1df3d2" + ] + ] + }, + { + "id": "9319d7d4f34c6d22", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, + "width": 3, + "height": 1, + "name": "rotor_angle_label", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 790, + "y": 2220, + "wires": [] + }, + { + "id": "1610895f430b9aca", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_angle", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 420, + "y": 2460, + "wires": [ + [ + "0f3367983bb8e159" + ] + ] + }, + { + "id": "96a9febc0928b6f0", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 12, + "width": 3, + "height": 1, + "name": "tt_angle_label", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 780, + "y": 2460, + "wires": [] + }, + { + "id": "e2c5ea8c16a5ea32", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, + "width": 6, + "height": 1, + "name": "rotor", + "label": "ROTOR", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 1820, + "wires": [] + }, + { + "id": "277037c4716d85bf", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_dir", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 410, + "y": 2500, + "wires": [ + [ + "c9d2e31514def4fc" + ] + ] + }, + { + "id": "1361134e9847f003", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 24, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 420, + "y": 2260, + "wires": [ + [ + "523717b0f218a5fd" + ] + ] + }, + { + "id": "6b0d58943ecb8bb2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 14, + "width": 3, + "height": 1, + "name": "tt_dir_label", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 770, + "y": 2500, + "wires": [] + }, + { + "id": "08f93dd2aeedb391", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, + "width": 3, + "height": 1, + "name": "rotor_dir_label", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 780, + "y": 2260, + "wires": [] + }, + { + "id": "46b91bef44714366", + "type": "link in", + "z": "e43a27722b508115", + "name": "advanced settings", + "links": [ + "8750ad979e9ea246" + ], + "x": 95, + "y": 100, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "8750ad979e9ea246", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "46b91bef44714366" + ], + "x": 955, + "y": 480, + "wires": [] + }, + { + "id": "2522f888dc58972f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_before", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 450, + "y": 2600, + "wires": [ + [ + "5c752757090c49d2" + ] + ] + }, + { + "id": "30e8df3d616512d8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_gain", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "10", + "step": "0.1", + "className": "", + "x": 420, + "y": 2640, + "wires": [ + [ + "a1769f0277834f6d" + ] + ] + }, + { + "id": "d855d926df89d65b", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_contrast", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2760, + "wires": [ + [ + "1a8b0ba21b4f3005", + "654bc70a18820828" + ] + ] + }, + { + "id": "7617517dc8ba2859", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_saturation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2800, + "wires": [ + [ + "dc8fc962ff7d594b", + "e64feb03a791ca33" + ] + ] + }, + { + "id": "cbaa23c34e10fae1", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_jpeg_q", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 3, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "100", + "step": "1", + "className": "", + "x": 410, + "y": 2840, + "wires": [ + [ + "00e7836ccb3c4d0c" + ] + ] + }, + { + "id": "bbe443b039a14e21", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, + "width": 3, + "height": 1, + "name": "delay_before", + "label": "Delay before", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2600, + "wires": [] + }, + { + "id": "d320ed3d701e6cc2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, + "width": 3, + "height": 1, + "name": "gain", + "label": "Gain", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2640, + "wires": [] + }, + { + "id": "f5834dd4646c8af9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, + "width": 3, + "height": 1, + "name": "contrast", + "label": "Contrast", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2760, + "wires": [] + }, + { + "id": "ae9a4e19469813ef", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, + "width": 3, + "height": 1, + "name": "saturation", + "label": "Saturation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2800, + "wires": [] + }, + { + "id": "bd629d0d31233c8b", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 2, + "width": 3, + "height": 1, + "name": "jpegQ", + "label": "Jpeg Quality", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2840, + "wires": [] + }, + { + "id": "e89f61dbe6a6cffe", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ext", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 3, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3000, + "wires": [ + [ + "885bc559fafec5f2" + ] + ] + }, + { + "id": "ece38cb172a12d75", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 2, + "width": 4, + "height": 1, + "name": "ext", + "label": "External Camera", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3000, + "wires": [] + }, + { + "id": "70014da0b6ab6698", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3040, + "wires": [ + [ + "f70321c96bf81360" + ] + ] + }, + { + "id": "29634ea5f6d666df", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 4, + "width": 4, + "height": 1, + "name": "light1", + "label": "Light 1", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3040, + "wires": [] + }, + { + "id": "2544963852c6881a", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 7, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3080, + "wires": [ + [ + "95e1603bbd06a69d" + ] + ] + }, + { + "id": "27903533cd85a59e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 6, + "width": 4, + "height": 1, + "name": "light2", + "label": "Light 2", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3080, + "wires": [] + }, + { + "id": "a1394401246eb735", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotordir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 9, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3120, + "wires": [ + [ + "a8f92ea6bf394640" + ] + ] + }, + { + "id": "bc0aa4bacdfa94ea", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 8, + "width": 4, + "height": 1, + "name": "rotordir", + "label": "Rotor direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3120, + "wires": [] + }, + { + "id": "f15ca4518b5f223e", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotorstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 11, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3160, + "wires": [ + [ + "06397bb46b3bb541" + ] + ] + }, + { + "id": "0d2924b160e7e383", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 10, + "width": 4, + "height": 1, + "name": "rotorstep", + "label": "Rotor step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3160, + "wires": [] + }, + { + "id": "49900bb9047dd965", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotoren", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 13, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3200, + "wires": [ + [ + "687dcdc1ede11700" + ] + ] + }, + { + "id": "a4d743ca73ee1622", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 12, + "width": 4, + "height": 1, + "name": "rotoren", + "label": "Rotor enable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3200, + "wires": [] + }, + { + "id": "5a90224dc998b417", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttdir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 15, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3240, + "wires": [ + [ + "e220740c0d38ccb0" + ] + ] + }, + { + "id": "67dc1b544c4ddf9f", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 14, + "width": 4, + "height": 1, + "name": "ttdir", + "label": "Turntable direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3240, + "wires": [] + }, + { + "id": "d2364ab09627fe94", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 17, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3280, + "wires": [ + [ + "79d7e5a705ab813a" + ] + ] + }, + { + "id": "145b67ac40721ba6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 16, + "width": 4, + "height": 1, + "name": "ttstep", + "label": "Turntable step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3280, + "wires": [] + }, + { + "id": "eef25405472acfee", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 19, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3320, + "wires": [ + [ + "12d20f2274bcc511" + ] + ] + }, + { + "id": "35eb252a41413531", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 18, + "width": 4, + "height": 1, + "name": "endstop1", + "label": "Endstop Rotor", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3320, + "wires": [] + }, + { + "id": "5fcef1cb2e9e4788", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "confirm", + "x": 680, + "y": 480, + "wires": [ + [ + "29745a36fc157f3f" + ] + ] + }, + { + "id": "f06a7bcad524e9f9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", + "outputs": 1, + "x": 530, + "y": 480, + "wires": [ + [ + "5fcef1cb2e9e4788" + ] + ] + }, + { + "id": "f455fb39039617ae", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_rotation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "270", + "step": "90", + "className": "", + "x": 410, + "y": 2880, + "wires": [ + [ + "3019576de193d9d6" + ] + ] + }, + { + "id": "fdfbc900fe424eb9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, + "width": 3, + "height": 1, + "name": "cam_rot", + "label": "Image Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2880, + "wires": [] + }, + { + "id": "c3699d6b9664ccca", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2060, + "wires": [ + [ + "dfdebe10dbf0e198" + ] + ] + }, + { + "id": "78e256083f59f66f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2060, + "wires": [ + [] + ] + }, + { + "id": "0f9141b401322374", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2180, + "wires": [ + [ + "9a56c087d941f1da" + ] + ] + }, + { + "id": "29f576be9e292232", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2180, + "wires": [ + [] + ] + }, + { + "id": "23e3099b34c4e475", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2220, + "wires": [ + [ + "0dfc86d90258f9bb" + ] + ] + }, + { + "id": "c4b5a38c5c1df3d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2220, + "wires": [ + [] + ] + }, + { + "id": "79a14162ac805fac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2260, + "wires": [ + [ + "1361134e9847f003" + ] + ] + }, + { + "id": "523717b0f218a5fd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2260, + "wires": [ + [] + ] + }, + { + "id": "f5cf780f3fa8997e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2100, + "wires": [ + [ + "b03e8b51187e88eb" + ] + ] + }, + { + "id": "11fd3363416433f9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2100, + "wires": [ + [] + ] + }, + { + "id": "02060b3f3b294563", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2140, + "wires": [ + [ + "543e1690693acbeb" + ] + ] + }, + { + "id": "e8b24efb0f30288e", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2140, + "wires": [ + [] + ] + }, + { + "id": "de1ad8b27b72a5ac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nvar steps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2300, + "wires": [ + [ + "c6642c7470d3820c" + ] + ] + }, + { + "id": "ed4d587cb4feb064", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2420, + "wires": [ + [ + "721b9680a3fa460e" + ] + ] + }, + { + "id": "5b02160c33605ae7", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2460, + "wires": [ + [ + "1610895f430b9aca" + ] + ] + }, + { + "id": "304c135ec09801e3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2500, + "wires": [ + [ + "277037c4716d85bf" + ] + ] + }, + { + "id": "a91dcbe0f9a2416a", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2340, + "wires": [ + [ + "6aae9d4fddf08cc0" + ] + ] + }, + { + "id": "6b2eb1cb95e573f9", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2380, + "wires": [ + [ + "10687d331a732790" + ] + ] + }, + { + "id": "eef89545ec0f6aa8", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2300, + "wires": [ + [] + ] + }, + { + "id": "b1b4678827d3a6dd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2420, + "wires": [ + [] + ] + }, + { + "id": "0f3367983bb8e159", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2460, + "wires": [ + [] + ] + }, + { + "id": "c9d2e31514def4fc", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2500, + "wires": [ + [] + ] + }, + { + "id": "e50492d1e18f43c6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2340, + "wires": [ + [] + ] + }, + { + "id": "af88b9da72917d62", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2380, + "wires": [ + [] + ] + }, + { + "id": "43fe948b3e7234e2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2600, + "wires": [ + [ + "2522f888dc58972f" + ] + ] + }, + { + "id": "5c752757090c49d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2600, + "wires": [ + [] + ] + }, + { + "id": "435681b3f7625a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2640, + "wires": [ + [ + "30e8df3d616512d8" + ] + ] + }, + { + "id": "a1769f0277834f6d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2640, + "wires": [ + [] + ] + }, + { + "id": "1de07c7d285cbaf3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2760, + "wires": [ + [ + "d855d926df89d65b" + ] + ] + }, + { + "id": "1a8b0ba21b4f3005", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2760, + "wires": [ + [] + ] + }, + { + "id": "ebc9e283468eda31", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2800, + "wires": [ + [ + "7617517dc8ba2859" + ] + ] + }, + { + "id": "dc8fc962ff7d594b", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2800, + "wires": [ + [] + ] + }, + { + "id": "60d641613527c736", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2840, + "wires": [ + [ + "cbaa23c34e10fae1" + ] + ] + }, + { + "id": "00e7836ccb3c4d0c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2840, + "wires": [ + [] + ] + }, + { + "id": "7f24c0c34a88ba04", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2880, + "wires": [ + [ + "f455fb39039617ae" + ] + ] + }, + { + "id": "3019576de193d9d6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2880, + "wires": [ + [] + ] + }, + { + "id": "77bb7dc529d63a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3000, + "wires": [ + [ + "e89f61dbe6a6cffe" + ] + ] + }, + { + "id": "885bc559fafec5f2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3000, + "wires": [ + [] + ] + }, + { + "id": "cc6dabe017a9c8a8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3320, + "wires": [ + [ + "eef25405472acfee" + ] + ] + }, + { + "id": "12d20f2274bcc511", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3320, + "wires": [ + [] + ] + }, + { + "id": "dcb9fed8122759fd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3040, + "wires": [ + [ + "70014da0b6ab6698" + ] + ] + }, + { + "id": "f70321c96bf81360", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3040, + "wires": [ + [] + ] + }, + { + "id": "013d2057c2347a62", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3080, + "wires": [ + [ + "2544963852c6881a" + ] + ] + }, + { + "id": "95e1603bbd06a69d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3080, + "wires": [ + [] + ] + }, + { + "id": "f88bbf11d5aa9a14", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3120, + "wires": [ + [ + "a1394401246eb735" + ] + ] + }, + { + "id": "a8f92ea6bf394640", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3120, + "wires": [ + [] + ] + }, + { + "id": "301af70731e096e5", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3160, + "wires": [ + [ + "f15ca4518b5f223e" + ] + ] + }, + { + "id": "06397bb46b3bb541", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3160, + "wires": [ + [] + ] + }, + { + "id": "0456a9ec4c236c9e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3200, + "wires": [ + [ + "49900bb9047dd965" + ] + ] + }, + { + "id": "687dcdc1ede11700", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3200, + "wires": [ + [] + ] + }, + { + "id": "09d37ba08ec0f163", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3240, + "wires": [ + [ + "5a90224dc998b417" + ] + ] + }, + { + "id": "37d954a4cf7e87ea", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3280, + "wires": [ + [ + "d2364ab09627fe94" + ] + ] + }, + { + "id": "e220740c0d38ccb0", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3240, + "wires": [ + [] + ] + }, + { + "id": "79d7e5a705ab813a", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3280, + "wires": [ + [] + ] + }, + { + "id": "22ef66b0e2058be2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 360, + "wires": [ + [ + "cb3437ec113e1b6f" + ] + ] + }, + { + "id": "9ce01c8ba97932c1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 400, + "wires": [ + [ + "60fd0adce1cfeb82" + ] + ] + }, + { + "id": "81356177176eebcf", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 480, + "wires": [ + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "b78346ca3ce70c68", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 320, + "wires": [ + [ + "f0d8dbcca76a1926" + ] + ] + }, + { + "id": "e95b86cbac1b03b9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "3e4c15d7b538f816", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 670, + "y": 1540, + "wires": [ + [ + "3bf622f344172721" + ] + ] + }, + { + "id": "0f0871baf322b6d0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1820, + "wires": [ + [ + "6ebd15c61a5ca891" + ] + ] + }, + { + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin_label", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1820, + "wires": [ + [] + ] + }, + { + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, + "wires": [ + [ + "acd10a4c99ee8063" + ] + ] + }, + { + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, + "wires": [ + [ + "031d7697768d0e77" + ] + ] + }, + { + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, + "wires": [ + [ + "be1954dd71d2c94c" + ] + ] + }, + { + "id": "edb1c8fae8b65c82", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1860, + "wires": [ + [ + "3ad0f0f206e4a873" + ] + ] + }, + { + "id": "031d7697768d0e77", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1860, + "wires": [ + [] + ] + }, + { + "id": "462a8f3ca75fc3c8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1900, + "wires": [ + [ + "3b6d759ed5be647f" + ] + ] + }, + { + "id": "be1954dd71d2c94c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1900, + "wires": [ + [] + ] + }, + { + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax_label", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart_label", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, + "wires": [ + [ + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88", + "53681e53353db898" + ] + ] + }, + { + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, + "y": 940, + "wires": [ + [ + "ded3086945a6d4b5", + "6ea3cdab41f20f92" + ] + ] + }, + { + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, + "wires": [ + [ + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd", + "a74d78a1d186a833" + ] + ] + }, + { + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2540, + "wires": [ + [ + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" + ] + ] + }, + { + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3000, + "wires": [ + [ + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8" + ] + ] + }, + { + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 620, + "wires": [ + [ + "53e6681d7254d484" + ] + ] + }, + { + "id": "53e6681d7254d484", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 270, + "y": 620, + "wires": [ + [ + "c11e79cfa7bc10b7" + ] + ] + }, + { + "id": "c11e79cfa7bc10b7", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 620, + "wires": [ + [ + "307782d10c1acdaf" + ] + ] + }, + { + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 620, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "cca3300a8f0daf4d", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 750, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "654bc70a18820828", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_contrast?contrast=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2720, + "wires": [ + [] + ] + }, + { + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_saturation?saturation=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2680, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2560, + "wires": [ + [ + "e612073aded01a8f" + ] + ] + }, + { + "id": "0d92559980944ae3", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, + "width": 3, + "height": 1, + "name": "delay_after", + "label": "Delay after", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2560, + "wires": [] + }, + { + "id": "6281b2e6e081104d", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2560, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2560, + "wires": [ + [] + ] + }, + { + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 560, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 560, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 210, + "y": 980, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 220, + "y": 1020, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 240, + "y": 1060, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] + }, + { + "id": "a7d233f984009e2e", + "type": "function", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 440, + "y": 980, + "wires": [ + [ + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" + ] + ] + }, + { + "id": "65518f3d4e3095e5", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 1", + "links": [ + "200d4b9951b6e066" + ], + "x": 85, + "y": 980, + "wires": [ + [ + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" + ] + ] + }, + { + "id": "9b851aa999e86fd7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", + "outputs": 1, + "x": 670, + "y": 980, + "wires": [ + [ + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" + ] + ] + }, + { + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 870, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, + "wires": [] + }, + { + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", + "links": [ + "592ec13d8f8923a9" + ], + "x": 815, + "y": 1020, + "wires": [] + }, + { + "id": "1eef47e0074545a9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, + "wires": [ + [ + "c994c779e4bad800", + "36890eb99a2ca1cf" + ], + [] + ] + }, + { + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, + "wires": [ + [ + "1eef47e0074545a9" + ] + ] + }, + { + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", + "name": "", + "x": 670, + "y": 1020, + "wires": [] + }, + { + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, + "wires": [] + }, + { + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, + "wires": [ + [ + "85ad07b8f973bbe2" + ] + ] + }, + { + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "rotor_endstop_angle_label", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 820, + "y": 2020, + "wires": [] + }, + { + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, + "wires": [ + [] + ] + }, + { + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, + "wires": [ + [ + "6b7245c3dcb694c8" + ] + ] + }, + { + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, + "wires": [ + [ + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" + ] + ] + }, + { + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, + "wires": [ + [ + "253feafa5a2f8b1d" + ] + ] + }, + { + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, + "wires": [ + [] + ] + }, + { + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_enable_endstop_label", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 820, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 450, + "y": 1980, + "wires": [ + [ + "69516440e3997111", + "f036424d79645761" + ] + ] + }, + { + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, + "wires": [ + [ + "eefed04c25e3e4d6" + ] + ] + }, + { + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, + "wires": [ + [ + "2aaf7c7f0f0c146f" + ] + ] + }, + { + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", + "outputs": 1, + "x": 660, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3560, + "wires": [ + [ + "d0a1a4947a1137ca" + ] + ] + }, + { + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 540, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] + }, + { + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, + "wires": [ + [] + ] + }, + { + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3640, + "wires": [ + [ + "b5aba11033c5f952" + ] + ] + }, + { + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, + { + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "e98c1b83744bb863", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Delete Aborted", + "tooltip": "Delete aborted photosets", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 420, + "y": 520, + "wires": [ + [ + "7438a5bf5fcddec4" + ] + ] + }, + { + "id": "7438a5bf5fcddec4", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "delete_aborted", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('delete_aborted'):\n save('delete_aborted', state)\n", + "outputs": 1, + "x": 600, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "53681e53353db898", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'delete_aborted'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 520, + "wires": [ + [ + "e98c1b83744bb863" + ] + ] + }, + { + "id": "48386fdb54980ec7", + "type": "comment", + "z": "e43a27722b508115", + "name": "Shield", + "info": "", + "x": 90, + "y": 3760, + "wires": [] + }, + { + "id": "fbc5fc2e65311f8b", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 3", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3840, + "wires": [ + [ + "5618e266f6966ae6" + ] + ] + }, + { + "id": "5618e266f6966ae6", + "type": "function", + "z": "e43a27722b508115", + "name": "loadl", + "func": "var file = 'shield_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 170, + "y": 3840, + "wires": [ + [ + "c97113d841391e40" + ] + ] + }, + { + "id": "c97113d841391e40", + "type": "ui_dropdown", + "z": "e43a27722b508115", + "name": "", + "label": "Shield Type", + "tooltip": "", + "place": "Select option", + "group": "0b244f698c7ac9a2", + "order": 0, + "width": 0, + "height": 0, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "Green", + "value": "green", + "type": "str" + }, + { + "label": "Black", + "value": "black", + "type": "str" + } + ], + "payload": "", + "topic": "payload", + "topicType": "msg", + "className": "", + "x": 310, + "y": 3840, + "wires": [ + [ + "2b639346c1b56578" + ] + ] + }, + { + "id": "2b639346c1b56578", + "type": "function", + "z": "e43a27722b508115", + "name": "function 2", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'shield_type';\nconst current_shield = fs.readFileSync(filepath + file, 'utf8');\n\nvar current_choice = msg.payload\n\nif (current_choice != current_shield) {\n \n switch (current_choice) {\n case \"green\":\n fs.writeFile(filepath + 'pin_external', String(10), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(17), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(9), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(11), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(14), err => {\n if (err) {\n return\n }\n });\n break;\n case \"black\":\n fs.writeFile(filepath + 'pin_external', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(24), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(22), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(17), err => {\n if (err) {\n return\n }\n });\n break;\n case \"custom\":\n break;\n }\n\n fs.writeFile(filepath + file, current_choice, err => {\n if (err) {\n return\n }\n });\n}\n\nmsg.status = 'The new ' + current_choice + ' shield has been configured'\nmsg.topic = msg.status\nmsg.payload = 'Do you want to reboot now to apply the changes?'\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 460, + "y": 3840, + "wires": [ + [ + "137f032887544d74" + ] + ] + }, + { + "id": "137f032887544d74", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": false, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Reboot", + "x": 600, + "y": 3840, + "wires": [ + [ + "d2db49796fe0da79", + "d0d6820224b0ab0f" + ] + ] + }, + { + "id": "d2db49796fe0da79", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "print(msg['payload'])\nreturn msg", + "outputs": 1, + "x": 790, + "y": 3840, + "wires": [ + [] + ] + }, + { + "id": "d0d6820224b0ab0f", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 6", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 780, + "y": 3720, + "wires": [] + }, + { + "id": "a74d78a1d186a833", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotate_tt_first'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1760, + "wires": [ + [ + "4e1b38e60f4179b0" + ] + ] + }, + { + "id": "4e1b38e60f4179b0", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotate_tt_first", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 3, + "width": "3", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 430, + "y": 1760, + "wires": [ + [ + "0e14711b77c43c23" + ] + ] + }, + { + "id": "0e14711b77c43c23", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotate_tt_first'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1760, + "wires": [ + [] + ] + }, + { + "id": "b1d13cc1ebec82d7", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 2, + "width": 3, + "height": 1, + "name": "rotate_tt_first_label", + "label": "Rotate turntable first", + "format": "", + "layout": "row-left", + "className": "", + "x": 790, + "y": 1760, + "wires": [] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'stable'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, + "wires": [ + [ + "e23c514008cad1a1" + ] + ] + }, + { + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] + }, + { + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, + "wires": [ + [ + "4ce127c61c3c5966", + "beacc3dc5398fa79" + ] + ] + }, + { + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", + "outputs": 1, + "x": 290, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "beacc3dc5398fa79", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "e23c514008cad1a1", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 480, + "y": 140, + "wires": [] + }, + { + "id": "b0629875a30ae1d7", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nopenscan_version = load_str('openscan_version')\nopenscan_branch = load_str('openscan_branch')\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/' + openscan_version + '/update/' + openscan_version\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + '/update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\nmsg['url'] = url\nmsg['openscan_branch'] = openscan_branch\nmsg['openscan_version'] = openscan_version\n\nreturn msg, msg", + "outputs": 2, + "x": 390, + "y": 540, + "wires": [ + [ + "1bbe2d769f42c313" + ], + [ + "fefe45404bdb19c4", + "44573d9223b2a75d" + ] + ] + }, + { + "id": "c7b6d05a62172432", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Status:", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 210, + "y": 400, + "wires": [] + }, + { + "id": "fefe45404bdb19c4", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "check files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nopenscan_version = msg['openscan_version']\nopenscan_branch = msg['openscan_branch']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = msg['url']\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[openscan_branch]:\n filepath = msg[openscan_branch][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[openscan_branch][i]['filesize2'] = filesize\n if filesize == msg[openscan_branch][i]['filesize']:\n msg[openscan_branch][i]['update'] = False\n continue\n msg[openscan_branch][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "outputs": 1, + "x": 550, + "y": 560, + "wires": [ + [ + "1bbe2d769f42c313", + "ae92a328af306ebb" + ] + ] + }, + { + "id": "d0104e0163745993", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 115, + "y": 440, + "wires": [ + [ + "ec30638407332e43", + "49f1ecb29a3f84f4" + ] + ] + }, + { + "id": "ec30638407332e43", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadS", + "func": "var file = 'openscan_branch'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 440, + "wires": [ + [ + "2852023f3aa8db10" + ] + ] + }, + { + "id": "2852023f3aa8db10", + "type": "ui_dropdown", + "z": "a5557543ccff5889", + "name": "", + "label": "", + "tooltip": "", + "place": "Select option", + "group": "ddbd496e.93a288", + "order": 4, + "width": 2, + "height": 1, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "stable", + "value": "stable", + "type": "str" + }, + { + "label": "beta", + "value": "beta", + "type": "str" + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" + } + ], + "payload": "", + "topic": "topic", + "topicType": "msg", + "className": "", + "x": 390, + "y": 440, + "wires": [ + [ + "1e10b387ee30c486" + ] + ] + }, + { + "id": "1e10b387ee30c486", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'openscan_branch'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 520, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "274129c51b0b87ef", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 3, + "width": 4, + "height": 1, + "name": "", + "label": "Branch: ", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 650, + "y": 440, + "wires": [] + }, + { + "id": "51cd8c8643e6b46a", + "type": "ui_switch", + "z": "a5557543ccff5889", + "name": "", + "label": "Auto-check update availability", + "tooltip": "", + "group": "ddbd496e.93a288", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 449, + "y": 491, + "wires": [ + [ + "1ab4c6b4b232a022" + ] + ] + }, + { + "id": "1ab4c6b4b232a022", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 649, + "y": 491, + "wires": [ + [] + ] + }, + { + "id": "ae92a328af306ebb", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "NO", + "cancel": "YES", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 710, + "y": 560, + "wires": [ + [ + "2de63e8e3ae5fb0c", + "929281fef53e09f8" + ] + ] + }, + { + "id": "cbd0afc4aa7b302a", + "type": "link in", + "z": "a5557543ccff5889", + "name": "update status", + "links": [ + "1bbe2d769f42c313", + "42061b28cff81f99" + ], + "x": 115, + "y": 400, + "wires": [ + [ + "c7b6d05a62172432", + "c94623ddd9d95f78" + ] + ] + }, + { + "id": "1bbe2d769f42c313", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 665, + "y": 520, + "wires": [] + }, + { + "id": "7cf60615d93e696b", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Check Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 180, + "y": 560, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "2de63e8e3ae5fb0c", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "download files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\nopenscan_version = msg['openscan_version']\nopenscan_branch = msg['openscan_branch']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = msg['url']\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[openscan_branch]:\n if msg[openscan_branch][i]['update'] == False:\n continue\n \n filepath = msg[openscan_branch][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + '/' + msg[openscan_branch][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[openscan_branch][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[openscan_branch][i]['dst'])\n \n if msg[openscan_branch][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "outputs": 1, + "x": 880, + "y": 560, + "wires": [ + [ + "42061b28cff81f99", + "fe3a855fee9e28c6" + ] + ] + }, + { + "id": "929281fef53e09f8", + "type": "function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 850, + "y": 520, + "wires": [ + [ + "42061b28cff81f99" + ] + ] + }, + { + "id": "42061b28cff81f99", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 995, + "y": 520, + "wires": [] + }, + { + "id": "49f1ecb29a3f84f4", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 480, + "wires": [ + [ + "b0629875a30ae1d7", + "51cd8c8643e6b46a" + ] + ] + }, + { + "id": "fe3a855fee9e28c6", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "9bb0adbd716ce347", + "01c882fcc51b349c" + ], + "x": 995, + "y": 560, + "wires": [] + }, + { + "id": "5e7d5e4335d37794", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 95, + "y": 700, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "2bb5fe78e09fec8a", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", + "outputs": 1, + "x": 210, + "y": 700, + "wires": [ + [ + "dbc77052ac950624", + "d97c3068ef5fef96", + "73a3b828f862312b", + "901e31453b2bdff8", + "f983854748ee4763", + "5347c7c517f5e8c7", + "3a5016f7003cd72c", + "6d720c4a4ecd9475", + "6438b7d060a70d81" + ] + ] + }, + { + "id": "d97c3068ef5fef96", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "OS:", + "format": "{{msg.os}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 740, + "wires": [] + }, + { + "id": "73a3b828f862312b", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 8, + "width": 0, + "height": 0, + "name": "", + "label": "Flask:", + "format": "{{msg.flask}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 780, + "wires": [] + }, + { + "id": "dbc77052ac950624", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Device:", + "format": "{{msg.device}}", + "layout": "row-spread", + "className": "", + "x": 500, + "y": 700, + "wires": [] + }, + { + "id": "3f42560297fe6978", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "name": "Download LOG", + "order": 9, + "width": 6, + "height": 1, + "format": "\n
Download error log\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 180, + "y": 1060, + "wires": [ + [] + ] + }, + { + "id": "c94623ddd9d95f78", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", + "outputs": 1, + "x": 210, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "39a502b38837273d", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "1e7457ea9c2c5e09" + ], + "x": 245, + "y": 600, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "901e31453b2bdff8", + "type": "delay", + "z": "a5557543ccff5889", + "name": "", + "pauseType": "delay", + "timeout": "10", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 220, + "y": 740, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "f983854748ee4763", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "", + "format": "{{msg.osdate}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 820, + "wires": [] + }, + { + "id": "5347c7c517f5e8c7", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "CPU temp:", + "format": "{{msg.temp}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 860, + "wires": [] + }, + { + "id": "3a5016f7003cd72c", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "CPU memory:", + "format": "{{msg.cpu}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 900, + "wires": [] + }, + { + "id": "6d720c4a4ecd9475", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 6, + "width": 0, + "height": 0, + "name": "", + "label": "Swap memory:", + "format": "{{msg.swap}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 940, + "wires": [] + }, + { + "id": "6438b7d060a70d81", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 7, + "width": 0, + "height": 0, + "name": "", + "label": "Diskspace:", + "format": "{{msg.diskspace}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 980, + "wires": [] + }, + { + "id": "8d012912f302be85", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 7, + "width": 6, + "height": 1, + "passthru": false, + "label": "Show Details/Changelog", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 210, + "y": 640, + "wires": [ + [ + "5242607a723cc628" + ] + ] + }, + { + "id": "5242607a723cc628", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "Changelog", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "outputs": 1, + "x": 430, + "y": 640, + "wires": [ + [ + "573722197b15bf84" + ] + ] + }, + { + "id": "573722197b15bf84", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 640, + "wires": [ + [] + ] + }, + { + "id": "28cab3989dcf898b", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "name": "Download Config", + "order": 9, + "width": 0, + "height": 0, + "format": "\n\n
Download Config\n
\n
\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 530, + "y": 1020, + "wires": [ + [] + ] + }, + { + "id": "c5268070.c55a3", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "name": "Upload Btn", + "order": 8, + "width": "3", + "height": 1, + "format": "\n\n \n\n\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 510, + "y": 1060, + "wires": [ + [ + "5e18b80e617a3db8" + ] + ] + }, + { + "id": "5e18b80e617a3db8", + "type": "debug", + "z": "a5557543ccff5889", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 750, + "y": 1060, + "wires": [] + }, + { + "id": "44573d9223b2a75d", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 8", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 720, + "y": 380, + "wires": [] + }, + { + "id": "9b3e6a06c82a0f52", + "type": "link in", + "z": "87715429b0b1c9a3", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 55, + "y": 120, + "wires": [ + [ + "f128ca405d1e1e4d", + "07d7ce3dab5f1c11" + ] + ] + }, + { + "id": "cd0dc08fcb5968c8", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Successful Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 100, + "wires": [] + }, + { + "id": "f128ca405d1e1e4d", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics*.json|grep -i \\\"aborted\\\":false|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Successful Scans", + "x": 210, + "y": 120, + "wires": [ + [ + "cd0dc08fcb5968c8" + ], + [], + [] + ] + }, + { + "id": "b91b4d65f2090793", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Aborted Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 400, + "y": 160, + "wires": [] + }, + { + "id": "07d7ce3dab5f1c11", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics*.json|grep -i \\\"aborted\\\":true|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Aborted Scans", + "x": 200, + "y": 180, + "wires": [ + [ + "b91b4d65f2090793" + ], + [], + [] + ] + }, + { + "id": "5b3aa9a71591ba34", + "type": "comment", + "z": "87715429b0b1c9a3", + "name": "Statistics", + "info": "", + "x": 100, + "y": 40, + "wires": [] + } +] \ No newline at end of file diff --git a/update/2024-1o/beta/settings.js b/update/2024-1o/beta/settings.js new file mode 100644 index 0000000..b71b7f3 --- /dev/null +++ b/update/2024-1o/beta/settings.js @@ -0,0 +1,515 @@ +/** + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT + * + * It can contain any valid JavaScript code that will get run when Node-RED + * is started. + * + * Lines that start with // are commented out. + * Each entry should be separated from the entries above and below by a comma ',' + * + * For more information about individual settings, refer to the documentation: + * https://nodered.org/docs/user-guide/runtime/configuration + * + * The settings are split into the following sections: + * - Flow File and User Directory Settings + * - Security + * - Server Settings + * - Runtime Settings + * - Editor Settings + * - Node Settings + * + **/ +process.env.HOSTNAME = require('os').hostname(); + +module.exports = { + +/******************************************************************************* + * Flow File and User Directory Settings + * - flowFile + * - credentialSecret + * - flowFilePretty + * - userDir + * - nodesDir + ******************************************************************************/ + + /** The file containing the flows. If not set, defaults to flows_.json **/ + flowFile: "flows.json", + + /** By default, credentials are encrypted in storage using a generated key. To + * specify your own secret, set the following property. + * If you want to disable encryption of credentials, set this property to false. + * Note: once you set this property, do not change it - doing so will prevent + * node-red from being able to decrypt your existing credentials and they will be + * lost. + */ + credentialSecret: false, + + /** By default, the flow JSON will be formatted over multiple lines making + * it easier to compare changes when using version control. + * To disable pretty-printing of the JSON set the following property to false. + */ + flowFilePretty: true, + + /** By default, all user data is stored in a directory called `.node-red` under + * the user's home directory. To use a different location, the following + * property can be used + */ + //userDir: '/home/nol/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + + /** Node-RED scans the `nodes` directory in the userDir to find local node files. + * The following property can be used to specify an additional directory to scan. + */ + //nodesDir: '/home/nol/.node-red/nodes', + +/******************************************************************************* + * Security + * - adminAuth + * - https + * - httpsRefreshInterval + * - requireHttps + * - httpNodeAuth + * - httpStaticAuth + ******************************************************************************/ + + /** To password protect the Node-RED editor and admin API, the following + * property can be used. See http://nodered.org/docs/security.html for details. + */ + //adminAuth: { + // type: "credentials", + // users: [{ + // username: "admin", + // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", + // permissions: "*" + // }] + //}, + + /** The following property can be used to enable HTTPS + * This property can be either an object, containing both a (private) key + * and a (public) certificate, or a function that returns such an object. + * See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener + * for details of its contents. + */ + + /** Option 1: static object */ + //https: { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + //}, + + /** Option 2: function that returns the HTTP configuration object */ + // https: function() { + // // This function should return the options object, or a Promise + // // that resolves to the options object + // return { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + // } + // }, + + /** If the `https` setting is a function, the following setting can be used + * to set how often, in hours, the function will be called. That can be used + * to refresh any certificates. + */ + //httpsRefreshInterval : 12, + + /** The following property can be used to cause insecure HTTP connections to + * be redirected to HTTPS. + */ + //requireHttps: true, + + /** To password protect the node-defined HTTP endpoints (httpNodeRoot), + * including node-red-dashboard, or the static content (httpStatic), the + * following properties can be used. + * The `pass` field is a bcrypt hash of the password. + * See http://nodered.org/docs/security.html#generating-the-password-hash + */ + //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + +/******************************************************************************* + * Server Settings + * - uiPort + * - uiHost + * - apiMaxLength + * - httpServerOptions + * - httpAdminRoot + * - httpAdminMiddleware + * - httpNodeRoot + * - httpNodeCors + * - httpNodeMiddleware + * - httpStatic + * - httpStaticRoot + ******************************************************************************/ + + /** the tcp port that the Node-RED web server is listening on */ + uiPort: process.env.PORT || 80, + + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. + * To listen on all IPv6 addresses, set uiHost to "::", + * The following property can be used to listen on a specific interface. For + * example, the following would only allow connections from the local machine. + */ + //uiHost: "127.0.0.1", + + /** The maximum size of HTTP request that will be accepted by the runtime api. + * Default: 5mb + */ + //apiMaxLength: '5mb', + + /** The following property can be used to pass custom options to the Express.js + * server used by Node-RED. For a full list of available options, refer + * to http://expressjs.com/en/api.html#app.settings.table + */ + //httpServerOptions: { }, + + /** By default, the Node-RED UI is available at http://localhost:1880/ + * The following property can be used to specify a different root path. + * If set to false, this is disabled. + */ + httpAdminRoot: '/editor', + + /** The following property can be used to add a custom middleware function + * in front of all admin http routes. For example, to set custom http + * headers. It can be a single function or an array of middleware functions. + */ + // httpAdminMiddleware: function(req,res,next) { + // // Set the X-Frame-Options header to limit where the editor + // // can be embedded + // //res.set('X-Frame-Options', 'sameorigin'); + // next(); + // }, + + + /** Some nodes, such as HTTP In, can be used to listen for incoming http requests. + * By default, these are served relative to '/'. The following property + * can be used to specifiy a different root path. If set to false, this is + * disabled. + */ + //httpNodeRoot: '/red-nodes', + + /** The following property can be used to configure cross-origin resource sharing + * in the HTTP nodes. + * See https://github.com/troygoode/node-cors#configuration-options for + * details on its contents. The following is a basic permissive set of options: + */ + //httpNodeCors: { + // origin: "*", + // methods: "GET,PUT,POST,DELETE" + //}, + + /** If you need to set an http proxy please set an environment variable + * called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. + * For example - http_proxy=http://myproxy.com:8080 + * (Setting it here will have no effect) + * You may also specify no_proxy (or NO_PROXY) to supply a comma separated + * list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk + */ + + /** The following property can be used to add a custom middleware function + * in front of all http in nodes. This allows custom authentication to be + * applied to all http in nodes, or any other sort of common request processing. + * It can be a single function or an array of middleware functions. + */ + //httpNodeMiddleware: function(req,res,next) { + // // Handle/reject the request, or pass it on to the http in node by calling next(); + // // Optionally skip our rawBodyParser by setting this to true; + // //req.skipRawBodyParser = true; + // next(); + //}, + + /** When httpAdminRoot is used to move the UI to a different root path, the + * following property can be used to identify a directory of static content + * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot + */ + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + httpStatic: [ + {path: '/home/pi/OpenScan/tmp2/', root: "/tmp2/"} + ], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + +/******************************************************************************* + * Runtime Settings + * - lang + * - logging + * - contextStorage + * - exportGlobalContextKeys + * - externalModules + ******************************************************************************/ + + /** Uncomment the following to run node-red in your preferred language. + * Available languages include: en-US (default), ja, de, zh-CN, zh-TW, ru, ko + * Some languages are more complete than others. + */ + // lang: "de", + + /** Configure the logging output */ + logging: { + /** Only console logging is currently supported */ + console: { + /** Level of logging to be recorded. Options are: + * fatal - only those errors which make the application unusable should be recorded + * error - record errors which are deemed fatal for a particular request + fatal errors + * warn - record problems which are non fatal + errors + fatal errors + * info - record information about the general running of the application + warn + error + fatal errors + * debug - record information which is more verbose than info + info + warn + error + fatal errors + * trace - record very detailed logging + debug + info + warn + error + fatal errors + * off - turn off all logging (doesn't affect metrics or audit) + */ + level: "info", + /** Whether or not to include metric events in the log output */ + metrics: false, + /** Whether or not to include audit events in the log output */ + audit: false + } + }, + + /** Context Storage + * The following property can be used to enable context storage. The configuration + * provided here will enable file-based context that flushes to disk every 30 seconds. + * Refer to the documentation for further options: https://nodered.org/docs/api/context/ + */ + //contextStorage: { + // default: { + // module:"localfilesystem" + // }, + //}, + + /** `global.keys()` returns a list of all properties set in global context. + * This allows them to be displayed in the Context Sidebar within the editor. + * In some circumstances it is not desirable to expose them to the editor. The + * following property can be used to hide any property set in `functionGlobalContext` + * from being list by `global.keys()`. + * By default, the property is set to false to avoid accidental exposure of + * their values. Setting this to true will cause the keys to be listed. + */ + exportGlobalContextKeys: false, + + /** Configure how the runtime will handle external npm modules. + * This covers: + * - whether the editor will allow new node modules to be installed + * - whether nodes, such as the Function node are allowed to have their + * own dynamically configured dependencies. + * The allow/denyList options can be used to limit what modules the runtime + * will install/load. It can use '*' as a wildcard that matches anything. + */ + externalModules: { + // autoInstall: false, /** Whether the runtime will attempt to automatically install missing modules */ + // autoInstallRetry: 30, /** Interval, in seconds, between reinstall attempts */ + // palette: { /** Configuration for the Palette Manager */ + // allowInstall: true, /** Enable the Palette Manager in the editor */ + // allowUpload: true, /** Allow module tgz files to be uploaded and installed */ + // allowList: [], + // denyList: [] + // }, + // modules: { /** Configuration for node-specified modules */ + // allowInstall: true, + // allowList: [], + // denyList: [] + // } + }, + + +/******************************************************************************* + * Editor Settings + * - disableEditor + * - editorTheme + ******************************************************************************/ + + /** The following property can be used to disable the editor. The admin API + * is not affected by this option. To disable both the editor and the admin + * API, use either the httpRoot or httpAdminRoot properties + */ + //disableEditor: false, + + /** Customising the editor + * See https://nodered.org/docs/user-guide/runtime/configuration#editor-themes + * for all available options. + */ + editorTheme: { + /** The following property can be used to set a custom theme for the editor. + * See https://github.com/node-red-contrib-themes/theme-collection for + * a collection of themes to chose from. + */ + //theme: "", + palette: { + /** The following property can be used to order the categories in the editor + * palette. If a node's category is not in the list, the category will get + * added to the end of the palette. + * If not set, the following default order is used: + */ + //categories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], + }, + projects: { + /** To enable the Projects feature, set this value to true */ + enabled: false, + workflow: { + /** Set the default projects workflow mode. + * - manual - you must manually commit changes + * - auto - changes are automatically committed + * This can be overridden per-user from the 'Git config' + * section of 'User Settings' within the editor + */ + mode: "manual" + } + }, + codeEditor: { + /** Select the text editor component used by the editor. + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired + */ + lib: "monaco", + options: { + /** The follow options only apply if the editor is set to "monaco" + * + * theme - must match the file name of a theme in + * packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/theme + * e.g. "tomorrow-night", "upstream-sunburst", "github", "my-theme" + */ + theme: "vs", + /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html + */ + //fontSize: 14, + //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", + //fontLigatures: true, + } + } + }, + +/******************************************************************************* + * Node Settings + * - fileWorkingDirectory + * - functionGlobalContext + * - functionExternalModules + * - nodeMessageBufferMaxLength + * - ui (for use with Node-RED Dashboard) + * - debugUseColors + * - debugMaxLength + * - execMaxBufferSize + * - httpRequestTimeout + * - mqttReconnectTime + * - serialReconnectTime + * - socketReconnectTime + * - socketTimeout + * - tcpMsgQueueSize + * - inboundWebSocketTimeout + * - tlsConfigDisableLocalFiles + * - webSocketNodeVerifyClient + ******************************************************************************/ + + /** The working directory to handle relative file paths from within the File nodes + * defaults to the working directory of the Node-RED process. + */ + //fileWorkingDirectory: "", + + /** Allow the Function node to load additional npm modules directly */ + functionExternalModules: true, + + /** The following property can be used to set predefined values in Global Context. + * This allows extra node modules to be made available with in Function node. + * For example, the following: + * functionGlobalContext: { os:require('os') } + * will allow the `os` module to be accessed in a Function node using: + * global.get("os") + */ +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, + /** The maximum number of messages nodes will buffer internally as part of their + * operation. This applies across a range of nodes that operate on message sequences. + * defaults to no limit. A value of 0 also means no limit is applied. + */ + //nodeMessageBufferMaxLength: 0, + + /** If you installed the optional node-red-dashboard you can set it's path + * relative to httpNodeRoot + * Other optional properties include + * readOnly:{boolean}, + * middleware:{function or array}, (req,res,next) - http middleware + * ioMiddleware:{function or array}, (socket,next) - socket.io middleware + */ + ui: { path: "" }, + + /** Colourise the console output of the debug node */ + //debugUseColors: true, + + /** The maximum length, in characters, of any message sent to the debug sidebar tab */ + debugMaxLength: 1000, + + /** Maximum buffer size for the exec node. Defaults to 10Mb */ + //execMaxBufferSize: 10000000, + + /** Timeout in milliseconds for HTTP request connections. Defaults to 120s */ + //httpRequestTimeout: 120000, + + /** Retry time in milliseconds for MQTT connections */ + mqttReconnectTime: 15000, + + /** Retry time in milliseconds for Serial port connections */ + serialReconnectTime: 15000, + + /** Retry time in milliseconds for TCP socket connections */ + //socketReconnectTime: 10000, + + /** Timeout in milliseconds for TCP server socket connections. Defaults to no timeout */ + //socketTimeout: 120000, + + /** Maximum number of messages to wait in queue while attempting to connect to TCP socket + * defaults to 1000 + */ + //tcpMsgQueueSize: 2000, + + /** Timeout in milliseconds for inbound WebSocket connections that do not + * match any configured node. Defaults to 5000 + */ + //inboundWebSocketTimeout: 5000, + + /** To disable the option for using local files for storing keys and + * certificates in the TLS configuration node, set this to true. + */ + //tlsConfigDisableLocalFiles: true, + + /** The following property can be used to verify websocket connection attempts. + * This allows, for example, the HTTP request headers to be checked to ensure + * they include valid authentication information. + */ + //webSocketNodeVerifyClient: function(info) { + // /** 'info' has three properties: + // * - origin : the value in the Origin header + // * - req : the HTTP request + // * - secure : true if req.connection.authorized or req.connection.encrypted is set + // * + // * The function should return true if the connection should be accepted, false otherwise. + // * + // * Alternatively, if this function is defined to accept a second argument, callback, + // * it can be used to verify the client asynchronously. + // * The callback takes three arguments: + // * - result : boolean, whether to accept the connection or not + // * - code : if result is false, the HTTP error status to return + // * - reason: if result is false, the HTTP reason string to return + // */ + //}, +} diff --git a/update/2024-1o/meanwhile/OpenScan.py b/update/2024-1o/meanwhile/OpenScan.py new file mode 100644 index 0000000..f5ac509 --- /dev/null +++ b/update/2024-1o/meanwhile/OpenScan.py @@ -0,0 +1,317 @@ +basepath = '/home/pi/OpenScan/' +from os.path import isfile +import os + +def load_bool(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + if value == '1' or value == 'True' or value =='true': + value = True + else: + value = False + return value + +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + return True + +def load_str(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + return value + +def load_int(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = int(file.read().replace('\n','')) + return value + +def load_float(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = float(file.read().replace('\n','')) + return value + +def save(name, value): + filename = basepath+'settings/'+name + with open(filename, 'w+') as file: + file.write(str(value)) + return + +def OpenScanCloud(cmd, msg): + from requests import get + osc_user = 'openscan' + osc_pw = 'free' + osc_server = 'http://openscanfeedback.dnsuser.de:1334/' + + try: + r = get(osc_server + cmd, auth=(osc_user, osc_pw), params=msg) + except: + r = type('obj', (object,), {'status_code' : 404, 'text':None}) + return r + +def camera(cmd, msg = {}): + from requests import get + flask = 'http://127.0.0.1:1312/' + try: + r = get(flask + cmd, params=msg) + return r.status_code + except: + return 400 + +def motorrun(motor,angle,endstop=False): + #motor can be "rotor", "tt" or "extra" + import RPi.GPIO as GPIO + from time import sleep + from math import cos + msg = {'cmd':'set'} + + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + + spr = load_int(motor + '_stepsperrotation') + dirpin = load_int('pin_' + motor + '_dir') + steppin = load_int('pin_' + motor +'_step') + dir = load_int(motor + '_dir') + ramp = load_int(motor + '_accramp') + acc = load_float(motor + '_acc') + delay_init = load_float(motor + '_delay') + delay = delay_init + + step_count=int(angle*spr/360) * dir + GPIO.setup(dirpin, GPIO.OUT) + GPIO.setup(steppin, GPIO.OUT) + + if endstop: + endstop_pin = load_int('pin_' + motor + '_endstop') + endstop_pushed = load_bool(motor + '_endstop_pushed') + GPIO.setup(ES_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP) + + if (step_count>0): + GPIO.output(dirpin, GPIO.HIGH) + if(step_count<0): + GPIO.output(dirpin, GPIO.LOW) + step_count=-step_count + for x in range(step_count): + if endstop: + # Stop movement if endstop is pushed AND if rotor is moving and isn't going away from the endstop. + if GPIO.input(endstop_pin) == endstop_pushed and (motor == 'rotor' and GPIO.input(dirpin) == False): + i = 0 + while i <= 10: + if GPIO.input(endstop_pin) != endstop_pushed: + i = 11 + if i == 10: + return + i = i + 1 + + GPIO.output(steppin, GPIO.HIGH) + if x<=ramp and x<=step_count/2: + delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) + #delay=delay_init+(ramp-x)*(delay_init)/acc + elif step_count-x<=ramp and x>step_count/2: + delay = delay_init * (1-1/acc*cos(1*(ramp+x-step_count)/ramp)+1/acc) + #delay=delay_init+(ramp-step_count+x)*(delay_init)/acc + else: + delay = delay_init + sleep(delay) + GPIO.output(steppin, GPIO.LOW) + sleep(delay) + +def ringlight(number,state): + import RPi.GPIO as GPIO + msg = {'cmd':'set'} + pin = load_int('pin_ringlight' + str(number)) + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + GPIO.setup(pin, GPIO.OUT) + GPIO.output(pin, state) + +def take_photo(file): + from os import system + filepath = basepath + file + + model=load_str('model') + + shutter = str(load_int('cam_shutter')) + saturation = load_str('cam_saturation') + contrast = load_str('cam_contrast') + awbg_red = load_str('cam_awbg_red') + awbg_blue = load_str('cam_awbg_blue') + gain = load_str('cam_gain') + quality = load_int('cam_jpeg_quality') + filepath2 = '/home/pi/OpenScan/tmp/tmp.jpg' + #width = load_str('cam_resx') + #height = load_str('cam_resy') + timeout = load_str('cam_timeout') + cropx = load_int('cam_cropx')/200 + cropy = load_int('cam_cropy')/200 + rotation = load_int('cam_rotation') + AF = load_bool('cam_AFmode') + camera = load_str('camera') + + + if camera == 'imx519' and AF == True: + autofocus = ' --autofocus ' + else: + autofocus = '' + + if camera == "usb_webcam": + cmd = 'fswebcam -i 0 -r "1280x720" -F 5 --no-banner --jpeg 95 --save ' + filepath2 + else: + cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + ' >/dev/null 2>&1' + # cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + + system(cmd) + return cmd + +def get_points(samples=1): + from math import pi, sqrt, acos, atan2, cos, sin + + points = [] + phi = pi * (3. - sqrt(5.)) + for i in range(int(samples)): + y = 1 - (i / float(samples - 1)) * 2 + radius = sqrt(1 - y * y) + theta = phi * i + x = cos(theta) * radius + z = sin(theta) * radius + r=sqrt(x*x+y*y+z*z) + theta_neu=acos(z/r)*180/pi + phi_neu=atan2(y,x)*180/pi + points.append((theta_neu-90,phi_neu)) + points.sort() + return points + +def create_coordinates(angle_min, angle_max,point_count): + point_count_final=point_count + if angle_max < angle_min: + a = angle_min + angle_min = angle_max + angle_max = a + point_count=point_count*90/(angle_max-angle_min) + actual_points=0 + while actual_pointsangle_min and x20: + point_count=point_count+3 + else: + point_count=point_count+1 + return filtered + + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/2024-1o/meanwhile/OpenScanSettings.py b/update/2024-1o/meanwhile/OpenScanSettings.py new file mode 100755 index 0000000..45e7e4f --- /dev/null +++ b/update/2024-1o/meanwhile/OpenScanSettings.py @@ -0,0 +1,183 @@ +import json +import os +from datetime import datetime +from dataclasses import dataclass, asdict +from unicodedata import decimal + +@dataclass +class OpenScanSettings: + advanced_settings: bool + cam_awbg_blue: int + cam_awbg_red: int + cam_contrast: int + cam_cropx: int + cam_cropy: int + cam_delay_after: int + cam_delay_before: int + camera: str + cam_features: bool + cam_focus_max: float + cam_focus_min: float + cam_focuspeak: bool + cam_gain: int + cam_histogram: bool + cam_jpeg_quality: int + cam_mask: bool + cam_mask_threshold: int + cam_output_downscale: bool + cam_output_resolution: int + cam_preview_resolution: int + cam_rotation: int + cam_saturation: int + cam_sharparea: bool + cam_sharpness: int + cam_shutter: int + cam_stacksize: int + cam_timeout: int + datadog_enable: bool + delete_aborted: bool + diskspace_threshold: int + extra_acc: float + extra_accramp: int + extra_angle: int + extra_delay: int + extra_dir: int + extra_stepsperrotation: int + group_stack_photos: bool + hostname: str + interface_color: str + model: str + object_size: float + openscan_uuid: str + osc_credit: int + osc_limit_filesize: int + osc_limit_photos: int + osc_splitsize: int + pin_external: int + pin_extra_dir: int + pin_extra_enable: int + pin_extra_endstop: int + pin_extra_step: int + pin_ringlight1: int + pin_ringlight2: int + pin_rotor_dir: int + pin_rotor_enable: int + pin_rotor_endstop: int + pin_rotor_step: int + pin_tt_dir: int + pin_tt_step: int + raspberry_model: str + raspbian_codename: str + rotate_tt_first: bool + rotor_acc: int + rotor_accramp: int + rotor_angle: int + rotor_anglemax: int + rotor_anglemin:int + rotor_anglestart: int + rotor_delay: int + rotor_dir: int + rotor_enable_endstop: bool + rotor_endstop_angle: int + rotor_endstop_enable: bool + rotor_stepsperrotation: int + routine_photocount: int + routine_projectname: str + routine_secondpass: bool + sdcard_manfid: str + sdcard_name: str + shield_type: str + smb_enable: bool + ssh_enable: bool + status_cloud: str + status_internal_cam: str + telegram_client_id: str + telegram_enable: bool + terms: bool + tt_acc: float + tt_accramp: int + tt_angle: int + tt_delay: int + tt_dir: int + tt_stepsperrotation: int + turntable_mode: bool + updateable: bool + update_auto: bool + uploadprogress: str + + @classmethod + def get_openscan_settings(cls): + settings = {} + blacklist = [ + 'architecture', + 'openscan_version', + 'openscan_branch', + 'token', + 'session_token', + 'telegram_api_token', + 'telegram_client_id', + 'status_uploadprogress', + 'raspberry_model', + 'sdcard_name', + 'sdcard_manfid', + 'uploadprogress' + ] # Add more keywords as needed + for field in cls.__dataclass_fields__: + if field not in blacklist: + try: + with open(f"/home/pi/OpenScan/settings/{field}", "r") as file: + value = file.read().strip() + field_type = cls.__annotations__[field] + if field_type == bool: + settings[field] = value.lower() == 'true' + elif field_type == int: + settings[field] = int(value) + elif field_type == float: + settings[field] = float(value) + else: + settings[field] = value + except FileNotFoundError: + print(f"Warning: File {field} not found. Skipping this field.") + except ValueError: + print(f"Warning: Could not convert value for {field}. Skipping this field.") + + return { + "version": "1.0", + "settings": settings + } + + @staticmethod + def export_settings_to_file(settings, file_path=None): + from datetime import datetime + + if file_path is None: + current_date = datetime.now().strftime("%Y-%m-%d") + file_path = f"openscan-settings-{current_date}.json" + + with open(file_path, "w") as json_file: + json.dump(settings, json_file, indent=4) + +def get_openscan_settings(): + return OpenScanSettings.get_openscan_settings() + +def export_settings_to_file(settings, file_path=None): + OpenScanSettings.export_settings_to_file(settings, file_path) + +def persist_settings_from_file(settings): + for field, value in settings.items(): + if field in OpenScanSettings.__dataclass_fields__: + field_type = OpenScanSettings.__annotations__[field] + try: + if field_type == bool: + value = str(value).lower() + elif field_type in (int, float): + value = str(field_type(value)) + else: + value = str(value) + + with open(f"/home/pi/OpenScan/settings/{field}", "w") as file: + file.write(value) + except ValueError: + print(f"Warning: Could not convert value for {field}. Skipping this field.") + except IOError: + print(f"Warning: Could not write to file for {field}. Skipping this field.") diff --git a/update/2024-1o/meanwhile/OpenScanStatistics.py b/update/2024-1o/meanwhile/OpenScanStatistics.py new file mode 100755 index 0000000..8b40088 --- /dev/null +++ b/update/2024-1o/meanwhile/OpenScanStatistics.py @@ -0,0 +1,74 @@ +import json +import os +from datetime import datetime +from dataclasses import dataclass + +@dataclass +class ScanData: + arch: str + openscan_version: str + openscan_branch: str + shield: str + date_init: str # Format: YYYY-MM-DD HH:MM + date_end: str # Format: YYYY-MM-DD HH:MM + num_photos: int + done_photos: int + camera: str + stack_size: int + telegram_enabled: bool + delete_aborted: bool + endstop_enabled: bool + group_stack_photos: bool + aborted: bool + +class ScanStatistics: + def __init__(self, filename: str = "/home/pi/OpenScan/statistics") -> None: + self.filename: str = filename + + def write_statistics(self, scan_data: ScanData) -> None: + data: dict = scan_data.__dict__ # Convert dataclass to dictionary + + # Parse date_init to get year and month + date_object: datetime = datetime.strptime(scan_data.date_init, "%Y-%m-%d %H:%M") + record_filename: str = os.path.join(self.filename, f"statistics-{date_object.year}-{date_object.month:02d}.json") + + # Append the new data as a new line + with open(record_filename, "a") as json_file: + json.dump(data, json_file, separators=(',', ':'), indent=None) # Collapsed JSON + json_file.write('\n') # Add a newline after each entry + + def get_statistics_from_file(self): + ''' + get the required statistics as a dictionary + ''' + statistics = {} + directory = self.filename + + # Check if the directory exists + if not os.path.exists(directory): + return statistics + + # Process all CSV files in the directory + for filename in os.listdir(directory): + if filename.endswith('.csv'): + file_path = os.path.join(directory, filename) + with open(file_path, 'r') as file: + lines = file.readlines() + + # Process each line of the CSV file + for line in lines[1:]: # Skip header row + data = line.strip().split(',') + if len(data) < 2: # Ensure there's at least a key-value pair + continue + key, value = data[0], data[1] + if key not in statistics: + statistics[key] = {} + if value not in statistics[key]: + statistics[key][value] = 0 + statistics[key][value] += 1 + + # Find the most common value for each field + for key in statistics: + statistics[key] = max(statistics[key], key=statistics[key].get) + + return statistics \ No newline at end of file diff --git a/update/2024-1o/meanwhile/config.txt b/update/2024-1o/meanwhile/config.txt new file mode 100755 index 0000000..953df5f --- /dev/null +++ b/update/2024-1o/meanwhile/config.txt @@ -0,0 +1,34 @@ +# For more options and information see +# http://rpf.io/configtxt +# Some settings may impact device functionality. See link above for details + +# Additional overlays and parameters are documented /boot/overlays/README + +# Automatically load overlays for detected cameras +# camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[pi4] +# Run as fast as firmware / board allows +arm_boost=1 +#dtoverlay=imx519,cma-512 + +[all] +camera_auto_detect=0 +gpu_mem=256 +dtoverlay=imx519 \ No newline at end of file diff --git a/update/2024-1o/meanwhile/fla.py b/update/2024-1o/meanwhile/fla.py new file mode 100644 index 0000000..c66cc4b --- /dev/null +++ b/update/2024-1o/meanwhile/fla.py @@ -0,0 +1,558 @@ +from zipfile import ZipFile +from flask import Flask, request, redirect, send_file, send_from_directory +from flask_restx import Resource, Api, Namespace +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont +from time import sleep, time +from OpenScan import load_int, load_float, load_bool, ringlight, motorrun +from OpenScanSettings import OpenScanSettings, get_openscan_settings, export_settings_to_file +import RPi.GPIO as GPIO +from math import sqrt +import os +import math +#from skimage import feature, color, transform +import numpy as np +from scipy import ndimage +import socket +import zipfile + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +app = Flask(__name__) +api = Api(app, version='1.0', title='OpenScan API', description='API for OpenScan') + +v1 = Namespace('v1', description='API v1') +# Create a namespace for system operations +system_ns = Namespace('system', description='System operations') +camera_ns = Namespace('camera', description='Camera operations') +motor_ns = Namespace('motor', description='Motor operations') + +api.add_namespace(v1, path='/v1') +api.add_namespace(system_ns, path='/v1/system') +api.add_namespace(camera_ns, path='/v1/camera') +api.add_namespace(motor_ns, path='/v1/motor') + +basedir = '/home/pi/OpenScan/' +timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + + +################################################################################################################### + + +@system_ns.route('/status') +class Status(Resource): + def get(self): + ''' + Get system status + ''' + import os + import json + from time import time + + if os.path.exists('/tmp/status.json'): + try: + with open('/tmp/status.json', 'r') as status_file: + status = json.load(status_file) + + elapsed_time = time() - status['start_time'] + estimated_total_time = (elapsed_time / status['current_photo']) * status['total_photos'] + time_remaining = max(0, estimated_total_time - elapsed_time) + + status.update({ + "status": "running", + "elapsed_time": int(elapsed_time), + "estimated_total_time": int(estimated_total_time), + "time_remaining": int(time_remaining) + }) + + return status, 200 + except Exception as e: + return {"error": f"Error reading status file: {str(e)}"}, 500 + else: + return {"status": "idle"}, 200 + +@system_ns.route('/get_settings') +class SendSettingsFile(Resource): + def get(self): + statistics_folder:str = '/home/pi/OpenScan/statistics/' + openscan_tmp_folder:str = '/home/pi/OpenScan/tmp2' + file_name:str = 'settings' + openscan_settings = get_openscan_settings() + export_settings_to_file(openscan_settings, openscan_tmp_folder + "/" + file_name + '.json') + + zip_path = os.path.join(openscan_tmp_folder, f"{file_name}.zip") + json_path = os.path.join(openscan_tmp_folder, f"{file_name}.json") + + with zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED) as zip_object: + zip_object.write(json_path, arcname=f"{file_name}.json") + + if os.path.exists(statistics_folder): + for stat_file in os.listdir(statistics_folder): + file_path = os.path.join(statistics_folder, stat_file) + if os.path.isfile(file_path): + zip_object.write(file_path, f'statistics/{stat_file}') + if os.path.exists(openscan_tmp_folder + "/" + file_name + ".zip"): + print("ZIP file created") + else: + print("ZIP file not created") + return send_from_directory(openscan_tmp_folder, file_name + ".zip", as_attachment=True) + +@system_ns.route('/get_statistics') +class GetStatistics(Resource): + def get(self): + '''Get statistics from the OpenScanStatistics module''' + try: + from OpenScanStatistics import ScanStatistics + + stats = ScanStatistics() + statistics = stats.get_statistics_from_file() + + return {'statistics': statistics}, 200 + except Exception as e: + return {'error': f'Error retrieving statistics: {str(e)}'}, 500 + +@system_ns.route('/shutdown') +class Shutdown(Resource): + @system_ns.doc(params={'token': 'Shutdown token for authentication'}) + def get(self): + '''Shutdown the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('shutdown -h now') + return {'message': 'Shutting down'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/reboot') +class Reboot(Resource): + @system_ns.doc(params={'token': 'Reboot token for authentication'}) + def get(self): + '''Reboot the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('reboot -h') + return {'message': 'Rebooting'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/ringlight') +class Ringlight(Resource): + @system_ns.doc(params={'state': 'Ringlight state (0 or 1)'}) + def get(self): + '''Set ringlight state''' + state = int(request.args.get('state')) + if state == 0: + ringlight(1, False) + ringlight(2, False) + else: + ringlight(1, True) + ringlight(2, True) + return {'message': f'Ringlight set to {state}'}, 200 + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) + + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') + + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wait 3-5s + return {'message': 'Auto focus triggered'}, 200 + +@motor_ns.route('/motor_run') +class MotorRun(Resource): + ''' + Run a motor + ''' + @motor_ns.doc(params={ + 'motor': 'Motor name (rotor, tt, extra)', + 'angle': 'Angle to rotate (integer)', + 'endstop': 'Enable endstop (optional, boolean)' + }) + @motor_ns.response(400, 'Bad Request') + def get(self): + '''Run a motor''' + motor = request.args.get('motor') + if not motor: + return {'error': 'Motor parameter is required'}, 400 + if motor not in ['rotor', 'tt', 'extra']: + return {'error': 'Invalid motor name'}, 400 + + try: + angle = int(request.args.get('angle')) + except (TypeError, ValueError): + return {'error': 'Angle must be an integer'}, 400 + + ES_enable = request.args.get('ES_enable', 'false').lower() == 'true' + ES_start_state = request.args.get('ES_start_state', 'true').lower() == 'true' + + try: + motorrun(motor, angle, ES_enable, ES_start_state) + except Exception as e: + return {'error': f'Error running motor: {str(e)}'}, 500 + + return {'message': f'Motor {motor} run to {angle} degrees'}, 200 + + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) diff --git a/update/2024-1o/meanwhile/flows.json b/update/2024-1o/meanwhile/flows.json new file mode 100644 index 0000000..1c5bbc8 --- /dev/null +++ b/update/2024-1o/meanwhile/flows.json @@ -0,0 +1,10207 @@ +[ + { + "id": "e6f4d02efb300ea9", + "type": "tab", + "label": "Init", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "481edaf6db5a7a54", + "type": "tab", + "label": "Scan", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "80a3942785a26c29", + "type": "tab", + "label": "Files", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "e43a27722b508115", + "type": "tab", + "label": "Settings", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "a5557543ccff5889", + "type": "tab", + "label": "Update", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "87715429b0b1c9a3", + "type": "tab", + "label": "Statistics", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", + "type": "ui_tab", + "name": "Scan", + "icon": "dashboard", + "order": 3, + "disabled": false, + "hidden": false + }, + { + "id": "5c06cb6bcc371ee6", + "type": "ui_base", + "theme": { + "name": "theme-dark", + "lightTheme": { + "default": "#0094CE", + "baseColor": "#0094CE", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "darkTheme": { + "default": "#097479", + "baseColor": "#097479", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "customTheme": { + "name": "Untitled Theme 1", + "default": "#4B7930", + "baseColor": "#4B7930", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false + }, + "themeState": { + "base-color": { + "default": "#097479", + "value": "#097479", + "edited": false + }, + "page-titlebar-backgroundColor": { + "value": "#097479", + "edited": false + }, + "page-backgroundColor": { + "value": "#111111", + "edited": false + }, + "page-sidebar-backgroundColor": { + "value": "#333333", + "edited": false + }, + "group-textColor": { + "value": "#0eb8c0", + "edited": false + }, + "group-borderColor": { + "value": "#555555", + "edited": false + }, + "group-backgroundColor": { + "value": "#333333", + "edited": false + }, + "widget-textColor": { + "value": "#eeeeee", + "edited": false + }, + "widget-backgroundColor": { + "value": "#097479", + "edited": false + }, + "widget-borderColor": { + "value": "#333333", + "edited": false + }, + "base-font": { + "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + } + }, + "angularTheme": { + "primary": "indigo", + "accents": "blue", + "warn": "red", + "background": "grey", + "palette": "light" + } + }, + "site": { + "name": "OpenScan", + "hideToolbar": "false", + "allowSwipe": "false", + "lockMenu": "false", + "allowTempTheme": "true", + "dateFormat": "DD/MM/YYYY", + "sizes": { + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, + "cx": 6, + "cy": 6, + "px": 0, + "py": 0 + } + } + }, + { + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 9 + }, + { + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 8 + }, + { + "id": "b5fdd57b.15eda8", + "type": "ui_group", + "name": "Main", + "tab": "15a222ed.d70a7d", + "order": 1, + "disp": false, + "width": 13, + "collapse": false + }, + { + "id": "db43d646.2074c8", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", + "order": 2, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "15a222ed.d70a7d", + "type": "ui_tab", + "name": "Files&Cloud", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "365a30d0dfa83e95", + "type": "ui_group", + "name": "settings", + "tab": "e23b837a9f040895", + "order": 1, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "ac7409105cfecac6", + "type": "ui_group", + "name": "advanced", + "tab": "e23b837a9f040895", + "order": 3, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "729f9ea6e3513c9b", + "type": "ui_group", + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "b3150b13e34b1fe8", + "type": "ui_tab", + "name": "OpenScan", + "icon": "dashboard", + "order": 1, + "disabled": false, + "hidden": true + }, + { + "id": "ddbd496e.93a288", + "type": "ui_group", + "name": "Manage Updates", + "tab": "d25e08b4.5b27e8", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "3ce32450.e0cffc", + "type": "ui_group", + "name": "System & Stats", + "tab": "d25e08b4.5b27e8", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "d25e08b4.5b27e8", + "type": "ui_tab", + "name": "Update & Info", + "icon": "dashboard", + "order": 6, + "disabled": false, + "hidden": false + }, + { + "id": "4390b2ebcbbe104c", + "type": "ui_group", + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "8ab79a98e536e0d6", + "type": "ui_group", + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Rotor", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 5, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 1, + "width": 1, + "height": 1 + }, + { + "id": "33b6d7317d1524b8", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "aaf5b874c52a58aa", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, + "height": 1 + }, + { + "id": "f8d8740dcbf499fb", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 11, + "width": 1, + "height": 1 + }, + { + "id": "7ac0cb556740d159", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, + "height": 1 + }, + { + "id": "4de2414e29020c74", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "90223f7ddc082321", + "order": 2, + "width": 7, + "height": 1 + }, + { + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 + }, + { + "id": "ce21673092264c38", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, + "height": 1 + }, + { + "id": "3f7b77f8a1675d27", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "12b719cba49817c9", + "order": 7, + "width": 4, + "height": 1 + }, + { + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 8, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "ac59b8fb186de073", + "type": "ui_group", + "name": "Statistics", + "tab": "656b4eb8b15dab8f", + "order": 3, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "656b4eb8b15dab8f", + "type": "ui_tab", + "name": "Statistics", + "icon": "dashboard", + "order": 7, + "disabled": false, + "hidden": false + }, + { + "id": "0b244f698c7ac9a2", + "type": "ui_group", + "name": "Shield Type", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "f622137daacdfebe", + "type": "ui_group", + "name": "Group 3", + "tab": "b3150b13e34b1fe8", + "order": 3, + "disp": true, + "width": 6 + }, + { + "id": "38d121ea5b2bd77d", + "type": "ui_group", + "name": "Turntable", + "tab": "457102eadc9ddb6c", + "order": 9, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "dfb4a60f.d788f8", + "type": "ui_group", + "name": "Data Export", + "tab": "48418b79.0f5834", + "order": 1, + "disp": true, + "width": "12" + }, + { + "id": "48418b79.0f5834", + "type": "ui_tab", + "name": "Dashboard", + "icon": "dashboard", + "order": 2 + }, + { + "id": "c33a1024a72aa169", + "type": "ui_group", + "name": "Default", + "tab": "cc6c4310cf7b61cc", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "cc6c4310cf7b61cc", + "type": "ui_tab", + "name": "Home", + "icon": "dashboard", + "order": 10, + "disabled": false, + "hidden": false + }, + { + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 520, + "wires": [ + [ + "949bafced17d66d6" + ] + ] + }, + { + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "a1f0ed7d5a9d670e", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.1", + "topic": "", + "x": 110, + "y": 60, + "wires": [ + [ + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6", + "d81572486f15cd7a" + ] + ] + }, + { + "id": "544d20f02215011a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'openscan_branch':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 60, + "wires": [ + [ + "c77552216a8bb781" + ] + ] + }, + { + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 540, + "y": 60, + "wires": [ + [ + "960912e90ba5b5bc" + ] + ] + }, + { + "id": "960912e90ba5b5bc", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244", + "9b3e6a06c82a0f52", + "fbc5fc2e65311f8b" + ], + "x": 645, + "y": 60, + "wires": [] + }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "168d72a54504b327", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "5/0.1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "5", + "topic": "", + "payload": "", + "payloadType": "str", + "x": 100, + "y": 440, + "wires": [ + [ + "6c6ef2255a7d39e5" + ] + ] + }, + { + "id": "6c6ef2255a7d39e5", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "repeat 5s/0.1s", + "mode": "link", + "links": [ + "61990987acd0f263", + "2415272f42ce468c", + "6bf8344af427a6ba" + ], + "x": 205, + "y": 440, + "wires": [] + }, + { + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", + "outputs": 1, + "x": 270, + "y": 140, + "wires": [ + [ + "eb1a2387a1eeea76" + ] + ] + }, + { + "id": "b1e2491c952f84c9", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, + "wires": [ + [ + "200d4b9951b6e066" + ] + ] + }, + { + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "65518f3d4e3095e5", + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 800, + "y": 40, + "wires": [ + [ + "544d20f02215011a" + ] + ] + }, + { + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 470, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", + "outputs": 1, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 600, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 680, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 640, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 720, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "8955d11554f55e63", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "", + "order": 1, + "width": 6, + "height": 3, + "passthru": false, + "label": "Install Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "date", + "topic": "", + "topicType": "str", + "x": 120, + "y": 820, + "wires": [ + [ + "1e7457ea9c2c5e09" + ] + ] + }, + { + "id": "1e7457ea9c2c5e09", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "update", + "mode": "link", + "links": [ + "39a502b38837273d" + ], + "x": 245, + "y": 820, + "wires": [] + }, + { + "id": "245e4341d4fb611c", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 790, + "y": 540, + "wires": [ + [ + "627406f3611511dc" + ] + ] + }, + { + "id": "627406f3611511dc", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "write", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 930, + "y": 540, + "wires": [ + [ + "50eeb3e362f9027f" + ] + ] + }, + { + "id": "88b1bddde110298a", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 650, + "y": 540, + "wires": [ + [ + "245e4341d4fb611c" + ] + ] + }, + { + "id": "50eeb3e362f9027f", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "1dffb799fdf10cbc", + "2afb6a45c73fa244", + "2e9b29c70969cf01", + "2f4c0f98.dee2", + "3876d5cbd248592b", + "592ec13d8f8923a9", + "5e7d5e4335d37794", + "9b3e6a06c82a0f52", + "9fd259de91de1da1", + "b4c843620c251c43", + "cb40b9341bd22a28", + "d0104e0163745993", + "d1efcd5fa9d25785", + "da61581182b7299e", + "e5f38b4a07a5e278", + "fbc5fc2e65311f8b", + "fd0258418489839d" + ], + "x": 1015, + "y": 540, + "wires": [] + }, + { + "id": "4f3121f158f06a61", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", + "outputs": 1, + "x": 860, + "y": 580, + "wires": [ + [] + ] + }, + { + "id": "4a8a04b1e5dca8fe", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "run rotor till endstop", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 690, + "y": 580, + "wires": [ + [ + "4f3121f158f06a61" + ] + ] + }, + { + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n
    \n
  • speed improvement 2-3x
  • \n
  • currently tested on OpenScan Mini + IMX519 with RPi 4
  • \n
  • optimized toolpath
  • \n
  • more responsive user interface
  • \n
  • hotspot mode (when no wireless network available ssid: openscan pw: opensource
  • \n
  • preview features and sharpness
  • \n
  • partial background masking
  • \n
  • no more autofocus --> instead you can set a min and max focus distance
  • \n
\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 580, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "e548168473aa85d6", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 5, + "width": 0, + "height": 0, + "passthru": false, + "label": "Statistics", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "5", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 100, + "y": 760, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "d81572486f15cd7a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "loadl", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'openscan_version'\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.openscan_version = String(data);\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 360, + "wires": [ + [ + "0d8c6bc7887fb3c2", + "fa6db57803ae2b6d" + ] + ] + }, + { + "id": "fa6db57803ae2b6d", + "type": "debug", + "z": "e6f4d02efb300ea9", + "name": "debug 7", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 430, + "y": 400, + "wires": [] + }, + { + "id": "6a3d9acbe097a3d2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 120, + "wires": [ + [ + "cb6ebdabaaf7d0da" + ] + ] + }, + { + "id": "7ef6f1b5c67201fe", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "86f7d1b2d763f6e2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 160, + "wires": [ + [ + "c8a3fde5206ce1ae" + ] + ] + }, + { + "id": "fd799c931139764d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 240, + "wires": [ + [ + "87be854db758a9a6" + ] + ] + }, + { + "id": "d5140d455122c49a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 280, + "wires": [ + [ + "9daea4bd57f7a00e" + ] + ] + }, + { + "id": "194f3590dd4f6e3d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "2de69452e829d780", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", + "label": "", + "tooltip": "", + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, + "height": 1, + "passthru": true, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 320, + "y": 80, + "wires": [ + [ + "734ac3bff2df6837" + ] + ] + }, + { + "id": "97170908e1f4ac55", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 80, + "wires": [ + [ + "58e565fea35cb667" + ] + ] + }, + { + "id": "734ac3bff2df6837", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 55, + "y": 80, + "wires": [ + [ + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" + ] + ] + }, + { + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/v1/camera/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", + "outputs": 1, + "x": 510, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "c7f5808d753480d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 170, + "y": 200, + "wires": [ + [ + "11f41a6030578ef4" + ] + ] + }, + { + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 200, + "wires": [ + [ + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "855cbcadef1163c5", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 840, + "wires": [ + [ + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" + ] + ] + }, + { + "id": "1a443e20a973d2f1", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw true", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 630, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "d1b87196ae5373ed", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw false", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 430, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "03d92601c62b79d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "4s/0.5", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "Repeat", + "payload": "0.1", + "payloadType": "str", + "x": 100, + "y": 840, + "wires": [ + [ + "855cbcadef1163c5" + ] + ] + }, + { + "id": "41e6a4649b6afbfb", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Take Preview Shot", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/v1/camera/picam2_take_photo')\n\nreturn msg\n", + "outputs": 1, + "x": 450, + "y": 800, + "wires": [ + [ + "1a443e20a973d2f1", + "296636b7467fc745" + ] + ] + }, + { + "id": "85a268108250ba88", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", + "order": 1, + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 450, + "y": 840, + "wires": [ + [ + "417f653ca0dfdcfc", + "180476141c2a44ad" + ] + ] + }, + { + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, + "wires": [] + }, + { + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, + "wires": [ + [ + "e864254b18c23dd1" + ] + ] + }, + { + "id": "e864254b18c23dd1", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int, load_bool\n\nif 'payload' not in msg:\n return\n\nrotor_endstop_enable = load_bool('rotor_endstop_enable')\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'), rotor_endstop_enable)\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'), rotor_endstop_enable)\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'))\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'))\n\n", + "outputs": 1, + "x": 780, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "180476141c2a44ad", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 880, + "wires": [ + [ + "8cbdbfecbd12ef83" + ] + ] + }, + { + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", + "outputs": 1, + "x": 870, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", + "outputs": 1, + "x": 440, + "y": 720, + "wires": [ + [ + "923be3b2b25224b4" + ] + ] + }, + { + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "c8a3fde5206ce1ae", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 160, + "wires": [ + [ + "034ec9f59e50a361", + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "034ec9f59e50a361", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, + "wires": [ + [ + "194f3590dd4f6e3d" + ] + ] + }, + { + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, + "wires": [ + [ + "2de69452e829d780" + ] + ] + }, + { + "id": "cb6ebdabaaf7d0da", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 120, + "wires": [ + [ + "7ef6f1b5c67201fe" + ] + ] + }, + { + "id": "82ecd3cd971cb7ea", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, + "height": 1, + "name": "projectname", + "label": "Projectname", + "format": "", + "layout": "row-left", + "className": "", + "x": 530, + "y": 40, + "wires": [] + }, + { + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, + "wires": [ + [ + "06e1e19835a9816e" + ] + ] + }, + { + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, + "wires": [ + [ + "1fe18f3b0b52aabd" + ] + ] + }, + { + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "7dd287f40385922f", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "start ", + "group": "365a30d0dfa83e95", + "order": 10, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-play", + "payload": "", + "payloadType": "date", + "topic": "enabled", + "topicType": "str", + "x": 130, + "y": 1040, + "wires": [ + [ + "33d94a04b96a2de0", + "6d15f717d5a11002", + "9a6b30a0175a8ecd" + ] + ] + }, + { + "id": "579f2211199fd6ab", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "stop", + "group": "365a30d0dfa83e95", + "order": 12, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-stop", + "payload": "numberofphotos", + "payloadType": "global", + "topic": "", + "topicType": "str", + "x": 490, + "y": 1100, + "wires": [ + [ + "1787f08ed7070ddd", + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "1787f08ed7070ddd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "stop", + "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "outputs": 1, + "x": 630, + "y": 1100, + "wires": [ + [] + ] + }, + { + "id": "e9b13dfd9f8d3711", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 395, + "y": 1000, + "wires": [] + }, + { + "id": "9654deebb668e012", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "1s", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 290, + "y": 1140, + "wires": [ + [ + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "8367cfa0bf5bc5df", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine", + "links": [ + "200d4b9951b6e066", + "8689e938.dd9e38", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 45, + "y": 1040, + "wires": [ + [ + "7dd287f40385922f" + ] + ] + }, + { + "id": "fb13752beddee9f2", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 535, + "y": 1060, + "wires": [] + }, + { + "id": "33d94a04b96a2de0", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1100, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "c1c044f3c2139f68", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 1140, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "1daf9e3a5bd5ab48", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 430, + "y": 1040, + "wires": [ + [ + "fb13752beddee9f2" + ] + ] + }, + { + "id": "6d15f717d5a11002", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 1000, + "wires": [ + [ + "e9b13dfd9f8d3711" + ] + ] + }, + { + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "# The contents of this file are embedded in the OpenScan app (Node-RED)\nfrom OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom OpenScanStatistics import ScanStatistics, ScanData\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\nfrom datetime import datetime\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname, remove\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\nimport json\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\nstats = ScanStatistics()\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/v1/camera/picam2_switch_mode?mode=1')\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\narchitecture = load_str(\"architecture\")\nopenscan_version = load_str(\"openscan_version\")\nopenscan_branch = load_str(\"openscan_branch\")\ncamera_model = load_str(\"camera\")\nshield = load_str(\"shield_type\")\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\ndelete_aborted = load_bool('delete_aborted')\nrotate_tt_first = load_bool('rotate_tt_first')\nrotor_endstop_enable = load_bool('rotor_endstop_enable')\nif rotor_endstop_enable:\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_current_timestamp():\n return datetime.now().strftime(\"%Y-%m-%d %H:%M\")\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/v1/camera/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/v1/camera/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n \n if rotate_tt_first:\n motorrun('tt',tt_angle)\n motorrun('rotor',rotor_angle, rotor_endstop_enable)\n else:\n motorrun('rotor',rotor_angle, rotor_endstop_enable)\n motorrun('tt',tt_angle)\n return\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/v1/camera/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\ncounter2 = 0\n\ndate_init = get_current_timestamp()\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\n\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n \n # Calculate time remaining and write status to /tmp/status as JSON\n elapsed_time = time() - starttime\n estimated_total_time = (elapsed_time / counter) * photocount * steps\n time_remaining = max(0, estimated_total_time - elapsed_time)\n \n status = {\n \"scan_name\": projectname,\n \"total_photos\": photocount,\n \"current_photo\": counter,\n \"stacksize\": steps,\n \"start_time\": int(starttime),\n }\n with open('/tmp/status.json', 'w') as status_file:\n json.dump(status, status_file)\n\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/v1/camera/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\ntry:\n remove('/tmp/status.json')\nexcept FileNotFoundError:\n pass # File doesn't exist, so no need to delete\nexcept Exception as e:\n print(f\"Error deleting /tmp/status.json: {e}\")\n\nmotorrun('rotor', -position_last[0], rotor_endstop_enable)\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\ndate_end = get_current_timestamp()\n\n\nif counter == photocount:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n aborted=False\nelse:\n aborted=True\n if delete_aborted:\n remove(zippath)\n else:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nscan_data = ScanData(\n arch=architecture,\n openscan_version=openscan_version,\n openscan_branch=openscan_branch,\n shield=shield,\n date_init=date_init,\n date_end=date_end,\n num_photos=photocount,\n done_photos=counter,\n camera=camera_model,\n stack_size=stacksize,\n telegram_enabled=telegram_enable,\n delete_aborted=delete_aborted,\n endstop_enabled=rotor_endstop_enable,\n group_stack_photos=group_stack_photos,\n aborted=aborted\n)\n\nstats.write_statistics(scan_data)\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, + "wires": [ + [ + "1daf9e3a5bd5ab48", + "795c85ad4f109567" + ] + ] + }, + { + "id": "afe47a9eaae6f67f", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, + "height": 1, + "name": "", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", + "className": "", + "x": 340, + "y": 40, + "wires": [] + }, + { + "id": "8608517d0567d63f", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 40, + "wires": [ + [ + "afe47a9eaae6f67f" + ] + ] + }, + { + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 55, + "y": 40, + "wires": [ + [ + "8608517d0567d63f" + ] + ] + }, + { + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, + "wires": [ + [ + "9774e7ad3b506354" + ] + ] + }, + { + "id": "9774e7ad3b506354", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 380, + "wires": [ + [ + "f0af909f3e739b22" + ] + ] + }, + { + "id": "39c744466a21735e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 40, + "wires": [ + [ + "fa181d22775c2ce6" + ] + ] + }, + { + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 80, + "wires": [ + [ + "c615034ea6b26174" + ] + ] + }, + { + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 480, + "wires": [ + [ + "237c2135cdad86ea" + ] + ] + }, + { + "id": "dd7fb8791d34c751", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 880, + "wires": [ + [ + "180476141c2a44ad" + ] + ] + }, + { + "id": "5baf89a2682265f7", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "enable led", + "links": [ + "eb1a2387a1eeea76" + ], + "x": 145, + "y": 880, + "wires": [ + [ + "dd7fb8791d34c751" + ] + ] + }, + { + "id": "6a26e8a7253d708c", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 40, + "wires": [ + [ + "39c744466a21735e" + ] + ] + }, + { + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, + "wires": [ + [ + "61aab497fa50898e" + ] + ] + }, + { + "id": "9fd259de91de1da1", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 735, + "y": 40, + "wires": [ + [ + "6a26e8a7253d708c", + "35ad7e55833836c1" + ] + ] + }, + { + "id": "fa181d22775c2ce6", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 40, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "c615034ea6b26174", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 80, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "ae5ee8787145906d", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import camera\ncamera('/v1/camera/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", + "outputs": 1, + "x": 1290, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "f0af909f3e739b22", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Features", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 420, + "wires": [ + [ + "710fc2dbb5ef0167" + ] + ] + }, + { + "id": "710fc2dbb5ef0167", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "d93c2b67bcf23b9a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 480, + "wires": [ + [ + "5e83b653850fa16e" + ] + ] + }, + { + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 95, + "y": 480, + "wires": [ + [ + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" + ] + ] + }, + { + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "c8b93b42c720b9cf", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", + "links": [ + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" + ], + "x": 85, + "y": 380, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 560, + "y": 960, + "wires": [] + }, + { + "id": "ea54fcc2.cfcc2", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "get dirs", + "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "outputs": 1, + "x": 480, + "y": 180, + "wires": [ + [ + "f3662f8c7d3d7a2d", + "01e4783e148c6698" + ] + ] + }, + { + "id": "2f4c0f98.dee2", + "type": "link in", + "z": "80a3942785a26c29", + "name": "filelist", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "a4f09e25.02569", + "ed35109311335099", + "fb13752beddee9f2" + ], + "x": 355, + "y": 220, + "wires": [ + [ + "ea54fcc2.cfcc2" + ] + ] + }, + { + "id": "952ce286.4ffd4", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 4, + "width": 6, + "height": 1, + "name": "Status", + "label": "Status", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 250, + "y": 60, + "wires": [] + }, + { + "id": "d4383424.7807c8", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "upload", + "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", + "outputs": 2, + "x": 530, + "y": 460, + "wires": [ + [ + "9a132ab1.b21658" + ], + [ + "3d16b3789632784d", + "9a132ab1.b21658" + ] + ] + }, + { + "id": "50710948.71c308", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "set", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 750, + "y": 180, + "wires": [ + [ + "ada1b6f7cccc9344", + "85839a17fb7b58b9" + ] + ] + }, + { + "id": "834046a4.647938", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 5, + "width": 6, + "height": 1, + "name": "Set", + "label": "Set:", + "format": "{{msg.payload.Name}}", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 220, + "wires": [] + }, + { + "id": "9a132ab1.b21658", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.true", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 780, + "y": 460, + "wires": [ + [ + "8689e938.dd9e38" + ] + ] + }, + { + "id": "3c67e97b.9d19a6", + "type": "function", + "z": "80a3942785a26c29", + "name": "enable", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 130, + "y": 340, + "wires": [ + [ + "7a93d1e18254685c", + "e434ef42bd6b92e8", + "d5d840183025d91b", + "ab9e90ab5a53a0dd", + "478994f671a3907d" + ] + ] + }, + { + "id": "bfc01f26.c32cf", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.false", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 500, + "wires": [ + [ + "f20f2dbc.0f123" + ] + ] + }, + { + "id": "b33d604c.5f1a6", + "type": "link in", + "z": "80a3942785a26c29", + "name": "enable cloud", + "links": [ + "4082b136.dae18", + "8689e938.dd9e38", + "bd75f33b8a57c522", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 35, + "y": 340, + "wires": [ + [ + "3c67e97b.9d19a6" + ] + ] + }, + { + "id": "f6bd1a04.470838", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "set", + "tot": "global" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 410, + "y": 460, + "wires": [ + [ + "d4383424.7807c8" + ] + ] + }, + { + "id": "4082b136.dae18", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "b33d604c.5f1a6", + "87574a42938afec4" + ], + "x": 715, + "y": 140, + "wires": [] + }, + { + "id": "f20f2dbc.0f123", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 515, + "y": 500, + "wires": [] + }, + { + "id": "8689e938.dd9e38", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 875, + "y": 460, + "wires": [] + }, + { + "id": "15de0ebb.616d61", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 380, + "wires": [ + [ + "a7d89487.ee8858" + ] + ] + }, + { + "id": "a7d89487.ee8858", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", + "outputs": 1, + "x": 690, + "y": 380, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "a4f09e25.02569", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2" + ], + "x": 775, + "y": 360, + "wires": [] + }, + { + "id": "7a93d1e18254685c", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "92c98e6ce7cd25f9" + ], + "x": 235, + "y": 500, + "wires": [] + }, + { + "id": "4d99c601c9881680", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "refresh", + "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", + "outputs": 2, + "x": 320, + "y": 180, + "wires": [ + [ + "ea54fcc2.cfcc2", + "b42e061fb1f1f3d7" + ], + [ + "6434e713f088012b" + ] + ] + }, + { + "id": "372e95797a3f2f3b", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "limit :)", + "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", + "outputs": 1, + "x": 90, + "y": 220, + "wires": [ + [ + "573edbfdb7500ddc" + ] + ] + }, + { + "id": "573edbfdb7500ddc", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 230, + "y": 220, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "dacb1f078b624e10", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 340, + "wires": [ + [ + "c8d65cc7c2ff7c36" + ] + ] + }, + { + "id": "92c98e6ce7cd25f9", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "7a93d1e18254685c", + "bd75f33b8a57c522" + ], + "x": 35, + "y": 180, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "3d16b3789632784d", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 770, + "y": 500, + "wires": [ + [] + ] + }, + { + "id": "6434e713f088012b", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 470, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "c8d65cc7c2ff7c36", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", + "outputs": 1, + "x": 690, + "y": 340, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "f4e9a4bd79b4221f", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 340, + "wires": [ + [ + "dacb1f078b624e10" + ] + ] + }, + { + "id": "2806bf08ea21216d", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 380, + "wires": [ + [ + "15de0ebb.616d61" + ] + ] + }, + { + "id": "61990987acd0f263", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 45, + "y": 60, + "wires": [ + [ + "51579603bce21e98" + ] + ] + }, + { + "id": "e8e488a6dd5d0b33", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "Download", + "order": 8, + "width": 3, + "height": 1, + "format": "\n
Download\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 880, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "0c387c0291d6c131", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 750, + "y": 260, + "wires": [ + [ + "e8e488a6dd5d0b33" + ] + ] + }, + { + "id": "e5f38b4a07a5e278", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 655, + "y": 220, + "wires": [ + [ + "834046a4.647938" + ] + ] + }, + { + "id": "e434ef42bd6b92e8", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "upload2", + "order": 7, + "width": 3, + "height": 1, + "format": "upload", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 460, + "wires": [ + [ + "f6bd1a04.470838" + ] + ] + }, + { + "id": "c46e10b9c201913e", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "refresh", + "order": 2, + "width": 4, + "height": 1, + "format": "refresh{{msg.text}}", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 160, + "y": 180, + "wires": [ + [ + "372e95797a3f2f3b", + "4d99c601c9881680" + ] + ] + }, + { + "id": "d5d840183025d91b", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del set", + "order": 11, + "width": 2, + "height": 1, + "format": "delete set", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 380, + "wires": [ + [ + "2806bf08ea21216d" + ] + ] + }, + { + "id": "ab9e90ab5a53a0dd", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del ", + "order": 10, + "width": 2, + "height": 1, + "format": "delete all", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 340, + "wires": [ + [ + "f4e9a4bd79b4221f" + ] + ] + }, + { + "id": "478994f671a3907d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "combine", + "order": 9, + "width": 2, + "height": 1, + "format": "combine", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 540, + "wires": [ + [ + "51bfd0fb7b1d292e" + ] + ] + }, + { + "id": "189c1eed09624a7b", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 580, + "wires": [ + [ + "1493398979a63775" + ] + ] + }, + { + "id": "51bfd0fb7b1d292e", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 420, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "da325be8e74179be", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", + "outputs": 1, + "x": 560, + "y": 580, + "wires": [ + [ + "ed35109311335099" + ] + ] + }, + { + "id": "ed35109311335099", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "2f4c0f98.dee2" + ], + "x": 655, + "y": 580, + "wires": [] + }, + { + "id": "1493398979a63775", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Combine", + "x": 420, + "y": 580, + "wires": [ + [ + "da325be8e74179be" + ] + ] + }, + { + "id": "ada1b6f7cccc9344", + "type": "link out", + "z": "80a3942785a26c29", + "name": "combine", + "mode": "link", + "links": [ + "6dd356510c446cf4" + ], + "x": 835, + "y": 180, + "wires": [] + }, + { + "id": "6dd356510c446cf4", + "type": "link in", + "z": "80a3942785a26c29", + "name": "combine", + "links": [ + "ada1b6f7cccc9344" + ], + "x": 175, + "y": 580, + "wires": [ + [ + "189c1eed09624a7b" + ] + ] + }, + { + "id": "b42e061fb1f1f3d7", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "397ab7f44b893c89", + "3876d5cbd248592b" + ], + "x": 435, + "y": 140, + "wires": [] + }, + { + "id": "b99505440832439f", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "diskspace", + "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", + "outputs": 1, + "x": 800, + "y": 100, + "wires": [ + [ + "92047434f8e9f927" + ] + ] + }, + { + "id": "92047434f8e9f927", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 950, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "f3662f8c7d3d7a2d", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "minute", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 650, + "y": 100, + "wires": [ + [ + "b99505440832439f" + ] + ] + }, + { + "id": "51579603bce21e98", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "read", + "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", + "outputs": 1, + "x": 130, + "y": 60, + "wires": [ + [ + "952ce286.4ffd4" + ] + ] + }, + { + "id": "9a5baae623355f9d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "preview", + "order": 6, + "width": 6, + "height": 6, + "format": "
\n\n\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1020, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "85839a17fb7b58b9", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "preview", + "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", + "outputs": 1, + "x": 880, + "y": 220, + "wires": [ + [ + "9a5baae623355f9d" + ] + ] + }, + { + "id": "01e4783e148c6698", + "type": "ui_table", + "z": "80a3942785a26c29", + "group": "b5fdd57b.15eda8", + "name": "", + "order": 1, + "width": 13, + "height": 7, + "columns": [ + { + "field": "Date", + "title": "Date", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Name", + "title": "Name", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Photos", + "title": "Photos", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Duration", + "title": "ΔT", + "width": "60", + "align": "left", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Size", + "title": "Size", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Status", + "title": "Status", + "width": "140", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + } + ], + "outputs": 1, + "cts": true, + "x": 610, + "y": 180, + "wires": [ + [ + "4082b136.dae18", + "50710948.71c308", + "834046a4.647938", + "0c387c0291d6c131" + ] + ] + }, + { + "id": "cb3437ec113e1b6f", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "SSH", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 3, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 390, + "y": 360, + "wires": [ + [ + "c24f61b87e3226dd" + ] + ] + }, + { + "id": "60fd0adce1cfeb82", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Samba", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "test2", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 400, + "wires": [ + [ + "441d3ef525e901da" + ] + ] + }, + { + "id": "c24f61b87e3226dd", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "ssh", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", + "outputs": 1, + "x": 530, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "c013e836e759a085", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "4390b2ebcbbe104c", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "label": "Terms Of Use", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 120, + "y": 320, + "wires": [ + [ + "b78346ca3ce70c68" + ] + ] + }, + { + "id": "f0d8dbcca76a1926", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "Agree", + "cancel": "Disagree", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 410, + "y": 320, + "wires": [ + [ + "e95b86cbac1b03b9" + ] + ] + }, + { + "id": "34374044c0030625", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "General", + "group": "4390b2ebcbbe104c", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

General Settings

Terms Of Use

In order to use the OpenScanCloud, please read the terms of use as files will be transmitted from your device to the OpenScan Servers.

SSH

SSH can be used to access the Raspberry Pi and modify core files of the operating system. Please deactivate, if you do not want to use this feature.

If you want to use it, the default user is pi, password: raspberry. Please change the password immediately. 

Samba

Samba s a network local file sharing server, which allows accessing the Raspberry Pi's file system through the explorer (and other programs like FileZilla). You can use it to transfer custom photo sets to the device in order to use the OpenScanCloud. Therefore, you need to transfer the zip file containing your photos to the following folder /OpenScan/scans/

You can access the Raspberry Pis file system by inserting the following line into your Windows explorer: 

\\\\OpenScan/PiShare/OpenScan/scans/

username: pi, password: raspberry

Please deactivate the local file sharing if you do not intend to use it

Advanced Settings

Enable a ton of additional settings, which should be changed only if you know what you are doing ;)

Model

Device model you are using: OpenScan Mini or OpenScan Classic. Setting the device affects the settings of the motor (gear ratio, acceleration, speed). You can change those values manually in the advanced settings.

Camera

A wide range of camera modules is supported (Pi camera v1.3, v2.1, HQ, Arducam IMX519, IMX290, IMX378, OV9281). If you encounter any issues with those models, please check the orientation of the camera ribbon cable and its connectors.

DSLR (gphoto) - connect a wide range of DSLR cameras to the device through USB. See GPhoto for a full list of supported devices.

External camera - triggering any camera through an isolated GPIO signal on the front side of the pi shield.

Shutdown/Reboot

Always use the shutdown button before you power off your Raspberry Pi.

Restore Default Settings

In case you want to restore the default settings

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "b2b6bf23c9989133", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Pinout", + "group": "70d0be671bf03ca7", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Pinout

ONLY CHANGE THE PINOUT IF YOU ARE ABSOLUTELY SURE! CHANGES CAN DAMAGE THE RASPBERRY PI AND ANY PERIPHERALS!


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "441d3ef525e901da", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "smb", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", + "outputs": 1, + "x": 530, + "y": 400, + "wires": [ + [] + ] + }, + { + "id": "3256bab150113a48", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Motor", + "group": "7a3279eea439bcdd", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Motor Settings

Turntable Mode

Activate turntable mode in order to deactivate the rotor. The routine will only move the turntable and take a given number of photos.

Rotor - Start Angle, Min and Max Angle

Since this version of OpenScan does not have an endstop (yet), it is necessary to tell the device its position when the routine is being started. 0° corresponds to the horizontal (natural) orientation.

After that, the device will equally space the image positions between angle min and angle max.

Rotor/Turntable

Steps per rotation -  defines the number of steps it takes to move the axis 360°. It is defined by A*B*C, where A is the number of steps for one revolution of the given stepper motor (normally 200), B is the microstepping used (normally 16), and C the gear ratio (1 for the turntable and 15 or 5,33 for the OpenScan Mini and Classic respectively)

Delay - time in microseconds between each step of the motor. Lower this value if the movement is too fast

Acceleration - a factor defining how fast the delay time between each step is being changed during acceleration and deceleration phases. Lower this value in order to make the movement smoother.

Acceleration ramp - the number of steps allowed for the acceleration processes. Increase this value, if you want smoother movement.

Manual Angle - Defines the degree value for the manual movement through the arrow buttons in the scan menu

Direction - If needed, reverse the movement (in case the arrow buttons and movement do not correspond). Alternatively, you can flip the motor cable 180° (BUT MAKE SURE TO POWER OFF THE DEVICE!)


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 140, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "7a186669a17daa71", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "camera", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Camera Settings

Jpeg quality

Value in percent, which usually does not need to be changed.

Downscale Preview

The preview image has to be scaled down depending on your network speed. If you want to have a higher quality preview image, you can increase this value, which defines the maximal width/height value. If the value is too high, the preview window might not update

Image Rotation

Change the image rotation, if needed.

Timeout

Defines the time in seconds, when the libcamera command (used for the camera modules) will timeout. Increase this value, if the camera does not get triggered in each position.

Delay Before/After

A fixed delay in seconds before and/or after a photo is taken. Increase this value when the photos have visual motion blur.

AWBG, Gain, Contrast, Saturation

Under most circumstances, you do not need to touch these values.

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 420, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "edac7dd292e7e486", + "type": "comment", + "z": "e43a27722b508115", + "name": "General Settings", + "info": "", + "x": 120, + "y": 280, + "wires": [] + }, + { + "id": "161b52034e578ee2", + "type": "comment", + "z": "e43a27722b508115", + "name": "Network", + "info": "", + "x": 100, + "y": 760, + "wires": [] + }, + { + "id": "f6d6cc35679ede63", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "more sets", + "label": "Advanced Settings", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 480, + "wires": [ + [ + "f06a7bcad524e9f9" + ] + ] + }, + { + "id": "29745a36fc157f3f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "more sets", + "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", + "outputs": 2, + "x": 820, + "y": 480, + "wires": [ + [ + "8750ad979e9ea246" + ], + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "bf23328f9fb11b22", + "type": "ui_ui_control", + "z": "e43a27722b508115", + "name": "change visibility", + "events": "all", + "x": 600, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "b37be1d222bc70c9", + "type": "inject", + "z": "e43a27722b508115", + "name": "1s_repeater", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "1", + "crontab": "", + "once": true, + "onceDelay": "2", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 150, + "y": 60, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "89eedf29b404f750", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, + "wires": [ + [ + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" + ] + ] + }, + { + "id": "2050de5d9e02f69f", + "type": "comment", + "z": "e43a27722b508115", + "name": "Info Texts", + "info": "", + "x": 100, + "y": 140, + "wires": [] + }, + { + "id": "ded3086945a6d4b5", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "check ip address", + "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", + "outputs": 1, + "x": 250, + "y": 940, + "wires": [ + [ + "3cfe464506f46ecd" + ] + ] + }, + { + "id": "3cfe464506f46ecd", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Your local IP:", + "format": "{{msg.ip}}", + "layout": "row-spread", + "className": "", + "x": 430, + "y": 940, + "wires": [] + }, + { + "id": "bd206ad109831e6a", + "type": "comment", + "z": "e43a27722b508115", + "name": "OpenScanCloud", + "info": "", + "x": 120, + "y": 1260, + "wires": [] + }, + { + "id": "b70a9a665c1e4d36", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Cloud-settings", + "group": "12b719cba49817c9", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

OpenScanCloud

OpenScanCloud is a free/donation-based cloud processing service, which will convert your photos into 3d models using latest photogrammetry technology. Feel free to support the project with a small donation at BuyMeACoffee.

The only requirement to use this service is a one-time, free-of-charge registration (which is solely an anti-spam measure). By filling out the registration form, you will receive an individual access token.

Register

In order to use the OpenScanCloud, you will have to enter your name and email. It might take 1-3 days to create the access token, which will be sent to your mail address. Please check your spam folder.

Enter Token

Please enter your individual token here in order to activate the cloud functionality. The token will be verified immediately. In case of any problems, please contact cloud@openscan.eu

Token

A shorted version of your token will be displayed here. Please include a copy of this shorted token in any support requests cloud@openscan.eu

Credit (GB)

Each token comes with a given amount of 'credit' which is another measure against spam. The given number in Gigabyte indicates the amount of data, that you can process on the servers. 

IMPORTANT: The credit can be increased at any time by sending a (nice) mail to cloud@openscan.eu

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 260, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "c9f0566601a3e130", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Number of Photos:", + "format": "{{msg.limit_photos}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 1400, + "wires": [] + }, + { + "id": "9bd86d27ea499a2a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Filesize (GB):", + "format": "{{msg.limit_filesize}}", + "layout": "row-spread", + "className": "", + "x": 390, + "y": 1440, + "wires": [] + }, + { + "id": "2c37f7030810d234", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Credit (GB):", + "format": "{{msg.credit}}", + "layout": "row-spread", + "className": "", + "x": 370, + "y": 1480, + "wires": [] + }, + { + "id": "f40286c18afd4501", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "save", + "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", + "outputs": 2, + "x": 750, + "y": 1340, + "wires": [ + [ + "455a5266017ea121", + "50f73cee213ec05c" + ], + [ + "264eece408043021" + ] + ] + }, + { + "id": "455a5266017ea121", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 890, + "y": 1300, + "wires": [ + [] + ] + }, + { + "id": "c368df68593bc2bf", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Token", + "tooltip": "", + "group": "12b719cba49817c9", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 350, + "y": 1360, + "wires": [ + [ + "18fd1afa768187b3" + ] + ] + }, + { + "id": "18fd1afa768187b3", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "Save?", + "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", + "outputs": 2, + "x": 470, + "y": 1360, + "wires": [ + [ + "418aea2ec65573a0" + ], + [ + "9792c89c5f4429f9" + ] + ] + }, + { + "id": "f90a98899b7a71d0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "text", + "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", + "outputs": 1, + "x": 230, + "y": 1360, + "wires": [ + [ + "c368df68593bc2bf" + ] + ] + }, + { + "id": "b4c843620c251c43", + "type": "link in", + "z": "e43a27722b508115", + "name": "token", + "links": [ + "960912e90ba5b5bc", + "50f73cee213ec05c", + "9792c89c5f4429f9", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1360, + "wires": [ + [ + "f90a98899b7a71d0" + ] + ] + }, + { + "id": "418aea2ec65573a0", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 1340, + "wires": [ + [ + "f40286c18afd4501" + ] + ] + }, + { + "id": "9792c89c5f4429f9", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "b4c843620c251c43" + ], + "x": 555, + "y": 1380, + "wires": [] + }, + { + "id": "264eece408043021", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "5d267acc10020091", + "3876d5cbd248592b" + ], + "x": 835, + "y": 1380, + "wires": [] + }, + { + "id": "3876d5cbd248592b", + "type": "link in", + "z": "e43a27722b508115", + "name": "OSCparameters", + "links": [ + "960912e90ba5b5bc", + "264eece408043021", + "b42e061fb1f1f3d7", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1400, + "wires": [ + [ + "5daca3ec47f8e7fc" + ] + ] + }, + { + "id": "50f73cee213ec05c", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "b4c843620c251c43", + "5d267acc10020091" + ], + "x": 835, + "y": 1340, + "wires": [] + }, + { + "id": "95578e54a9b61cba", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 250, + "y": 1540, + "wires": [ + [ + "d7a5693da7855da8" + ] + ] + }, + { + "id": "d7a5693da7855da8", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", + "outputs": 2, + "x": 390, + "y": 1540, + "wires": [ + [ + "2b02b97dd1614e52" + ], + [ + "183a629accb417b1" + ] + ] + }, + { + "id": "183a629accb417b1", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1580, + "wires": [ + [] + ] + }, + { + "id": "2b02b97dd1614e52", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1540, + "wires": [ + [ + "3e4c15d7b538f816" + ] + ] + }, + { + "id": "3bf622f344172721", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "SUBMIT", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 810, + "y": 1540, + "wires": [ + [ + "e431cb2b8d217cee" + ] + ] + }, + { + "id": "e431cb2b8d217cee", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", + "outputs": 1, + "x": 950, + "y": 1540, + "wires": [ + [ + "106874534890f229" + ] + ] + }, + { + "id": "a38d7fde5c73210f", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Register", + "group": "12b719cba49817c9", + "order": 6, + "width": 2, + "height": 1, + "passthru": false, + "label": "Register", + "tooltip": "testtesttest", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "Please enter your email address:", + "payloadType": "str", + "topic": "Requesting an OpenScanCloud Token", + "topicType": "str", + "x": 100, + "y": 1540, + "wires": [ + [ + "95578e54a9b61cba" + ] + ] + }, + { + "id": "106874534890f229", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 1090, + "y": 1540, + "wires": [ + [] + ] + }, + { + "id": "5daca3ec47f8e7fc", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", + "outputs": 1, + "x": 230, + "y": 1400, + "wires": [ + [ + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" + ] + ] + }, + { + "id": "f34de19d4cf810a9", + "type": "comment", + "z": "e43a27722b508115", + "name": "Motor", + "info": "", + "x": 90, + "y": 1740, + "wires": [] + }, + { + "id": "26c2b58e21f97475", + "type": "comment", + "z": "e43a27722b508115", + "name": "Camera", + "info": "", + "x": 90, + "y": 2560, + "wires": [] + }, + { + "id": "a8ec972bad47a9a8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Pinout", + "info": "", + "x": 90, + "y": 3020, + "wires": [] + }, + { + "id": "b03e8b51187e88eb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "Rotor_delay (ms)", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 18, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 450, + "y": 2160, + "wires": [ + [ + "11fd3363416433f9" + ] + ] + }, + { + "id": "6aae9d4fddf08cc0", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt delay", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 420, + "y": 2400, + "wires": [ + [ + "e50492d1e18f43c6" + ] + ] + }, + { + "id": "543e1690693acbeb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 20, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 420, + "y": 2200, + "wires": [ + [ + "e8b24efb0f30288e" + ] + ] + }, + { + "id": "9a56c087d941f1da", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 22, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "100", + "max": "5000", + "step": "100", + "className": "", + "x": 440, + "y": 2240, + "wires": [ + [ + "29f576be9e292232" + ] + ] + }, + { + "id": "dfdebe10dbf0e198", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotor_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 16, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 460, + "y": 2120, + "wires": [ + [ + "78e256083f59f66f" + ] + ] + }, + { + "id": "af8dfe78cbd0c301", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, + "width": 3, + "height": 1, + "name": "rotor_acc_label", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2200, + "wires": [] + }, + { + "id": "ee4b8908a5b83880", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, + "width": 3, + "height": 1, + "name": "rotor_accramp_label", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 800, + "y": 2240, + "wires": [] + }, + { + "id": "c4deaa38c1b0adbf", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, + "width": 3, + "height": 1, + "name": "rotor_delay_label", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 790, + "y": 2160, + "wires": [] + }, + { + "id": "baec873a95fff48a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, + "width": 3, + "height": 1, + "name": "rotor_steps_rotation_label", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 810, + "y": 2120, + "wires": [] + }, + { + "id": "355e89ab4e5484e4", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 1, + "width": 6, + "height": 1, + "name": "tt", + "label": "TURNTABLE", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 2360, + "wires": [] + }, + { + "id": "10687d331a732790", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_acc", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 410, + "y": 2440, + "wires": [ + [ + "af88b9da72917d62" + ] + ] + }, + { + "id": "721b9680a3fa460e", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_accramp", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "500", + "step": "1", + "className": "", + "x": 430, + "y": 2480, + "wires": [ + [ + "b1b4678827d3a6dd" + ] + ] + }, + { + "id": "c6642c7470d3820c", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "tt_stepsperrotation", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 450, + "y": 2360, + "wires": [ + [ + "eef89545ec0f6aa8" + ] + ] + }, + { + "id": "18e5918748660109", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 10, + "width": 3, + "height": 1, + "name": "tt_accramp_label", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2480, + "wires": [] + }, + { + "id": "8e805244dc1899e8", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 4, + "width": 3, + "height": 1, + "name": "tt_stepsperrotation_label", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 810, + "y": 2360, + "wires": [] + }, + { + "id": "a09e5fbea861bfb1", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 8, + "width": 3, + "height": 1, + "name": "tt_acc_label", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 770, + "y": 2440, + "wires": [] + }, + { + "id": "7b06448b3b222011", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 6, + "width": 3, + "height": 1, + "name": "tt_delay_label", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2400, + "wires": [] + }, + { + "id": "0dfc86d90258f9bb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 24, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 430, + "y": 2280, + "wires": [ + [ + "c4b5a38c5c1df3d2" + ] + ] + }, + { + "id": "9319d7d4f34c6d22", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, + "width": 3, + "height": 1, + "name": "rotor_angle_label", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 790, + "y": 2280, + "wires": [] + }, + { + "id": "1610895f430b9aca", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_angle", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 420, + "y": 2520, + "wires": [ + [ + "0f3367983bb8e159" + ] + ] + }, + { + "id": "96a9febc0928b6f0", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 12, + "width": 3, + "height": 1, + "name": "tt_angle_label", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 780, + "y": 2520, + "wires": [] + }, + { + "id": "e2c5ea8c16a5ea32", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, + "width": 6, + "height": 1, + "name": "rotor", + "label": "ROTOR", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 1820, + "wires": [] + }, + { + "id": "277037c4716d85bf", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_dir", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 410, + "y": 2560, + "wires": [ + [ + "c9d2e31514def4fc" + ] + ] + }, + { + "id": "1361134e9847f003", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 26, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 420, + "y": 2320, + "wires": [ + [ + "523717b0f218a5fd" + ] + ] + }, + { + "id": "6b0d58943ecb8bb2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 14, + "width": 3, + "height": 1, + "name": "tt_dir_label", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 770, + "y": 2560, + "wires": [] + }, + { + "id": "08f93dd2aeedb391", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 25, + "width": 3, + "height": 1, + "name": "rotor_dir_label", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 780, + "y": 2320, + "wires": [] + }, + { + "id": "46b91bef44714366", + "type": "link in", + "z": "e43a27722b508115", + "name": "advanced settings", + "links": [ + "8750ad979e9ea246" + ], + "x": 95, + "y": 100, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "8750ad979e9ea246", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "46b91bef44714366" + ], + "x": 955, + "y": 480, + "wires": [] + }, + { + "id": "2522f888dc58972f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_before", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 450, + "y": 2660, + "wires": [ + [ + "5c752757090c49d2" + ] + ] + }, + { + "id": "30e8df3d616512d8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_gain", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "10", + "step": "0.1", + "className": "", + "x": 420, + "y": 2700, + "wires": [ + [ + "a1769f0277834f6d" + ] + ] + }, + { + "id": "d855d926df89d65b", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_contrast", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2820, + "wires": [ + [ + "1a8b0ba21b4f3005", + "654bc70a18820828" + ] + ] + }, + { + "id": "7617517dc8ba2859", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_saturation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2860, + "wires": [ + [ + "dc8fc962ff7d594b", + "e64feb03a791ca33" + ] + ] + }, + { + "id": "cbaa23c34e10fae1", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_jpeg_q", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 3, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "100", + "step": "1", + "className": "", + "x": 410, + "y": 2900, + "wires": [ + [ + "00e7836ccb3c4d0c" + ] + ] + }, + { + "id": "bbe443b039a14e21", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, + "width": 3, + "height": 1, + "name": "delay_before", + "label": "Delay before", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2660, + "wires": [] + }, + { + "id": "d320ed3d701e6cc2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, + "width": 3, + "height": 1, + "name": "gain", + "label": "Gain", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2700, + "wires": [] + }, + { + "id": "f5834dd4646c8af9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, + "width": 3, + "height": 1, + "name": "contrast", + "label": "Contrast", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2820, + "wires": [] + }, + { + "id": "ae9a4e19469813ef", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, + "width": 3, + "height": 1, + "name": "saturation", + "label": "Saturation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2860, + "wires": [] + }, + { + "id": "bd629d0d31233c8b", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 2, + "width": 3, + "height": 1, + "name": "jpegQ", + "label": "Jpeg Quality", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2900, + "wires": [] + }, + { + "id": "e89f61dbe6a6cffe", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ext", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 3, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3060, + "wires": [ + [ + "885bc559fafec5f2" + ] + ] + }, + { + "id": "ece38cb172a12d75", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 2, + "width": 4, + "height": 1, + "name": "ext", + "label": "External Camera", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3060, + "wires": [] + }, + { + "id": "70014da0b6ab6698", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3100, + "wires": [ + [ + "f70321c96bf81360" + ] + ] + }, + { + "id": "29634ea5f6d666df", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 4, + "width": 4, + "height": 1, + "name": "light1", + "label": "Light 1", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3100, + "wires": [] + }, + { + "id": "2544963852c6881a", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 7, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3140, + "wires": [ + [ + "95e1603bbd06a69d" + ] + ] + }, + { + "id": "27903533cd85a59e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 6, + "width": 4, + "height": 1, + "name": "light2", + "label": "Light 2", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3140, + "wires": [] + }, + { + "id": "a1394401246eb735", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotordir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 9, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3180, + "wires": [ + [ + "a8f92ea6bf394640" + ] + ] + }, + { + "id": "bc0aa4bacdfa94ea", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 8, + "width": 4, + "height": 1, + "name": "rotordir", + "label": "Rotor direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3180, + "wires": [] + }, + { + "id": "f15ca4518b5f223e", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotorstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 11, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3220, + "wires": [ + [ + "06397bb46b3bb541" + ] + ] + }, + { + "id": "0d2924b160e7e383", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 10, + "width": 4, + "height": 1, + "name": "rotorstep", + "label": "Rotor step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3220, + "wires": [] + }, + { + "id": "49900bb9047dd965", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotoren", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 13, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3260, + "wires": [ + [ + "687dcdc1ede11700" + ] + ] + }, + { + "id": "a4d743ca73ee1622", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 12, + "width": 4, + "height": 1, + "name": "rotoren", + "label": "Rotor enable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3260, + "wires": [] + }, + { + "id": "5a90224dc998b417", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttdir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 15, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3300, + "wires": [ + [ + "e220740c0d38ccb0" + ] + ] + }, + { + "id": "67dc1b544c4ddf9f", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 14, + "width": 4, + "height": 1, + "name": "ttdir", + "label": "Turntable direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3300, + "wires": [] + }, + { + "id": "d2364ab09627fe94", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 17, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3340, + "wires": [ + [ + "79d7e5a705ab813a" + ] + ] + }, + { + "id": "145b67ac40721ba6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 16, + "width": 4, + "height": 1, + "name": "ttstep", + "label": "Turntable step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3340, + "wires": [] + }, + { + "id": "eef25405472acfee", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 19, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3380, + "wires": [ + [ + "12d20f2274bcc511" + ] + ] + }, + { + "id": "35eb252a41413531", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 18, + "width": 4, + "height": 1, + "name": "endstop1", + "label": "Endstop Rotor", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3380, + "wires": [] + }, + { + "id": "5fcef1cb2e9e4788", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "confirm", + "x": 680, + "y": 480, + "wires": [ + [ + "29745a36fc157f3f" + ] + ] + }, + { + "id": "f06a7bcad524e9f9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", + "outputs": 1, + "x": 530, + "y": 480, + "wires": [ + [ + "5fcef1cb2e9e4788" + ] + ] + }, + { + "id": "f455fb39039617ae", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_rotation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "270", + "step": "90", + "className": "", + "x": 410, + "y": 2940, + "wires": [ + [ + "3019576de193d9d6" + ] + ] + }, + { + "id": "fdfbc900fe424eb9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, + "width": 3, + "height": 1, + "name": "cam_rot", + "label": "Image Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2940, + "wires": [] + }, + { + "id": "c3699d6b9664ccca", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2120, + "wires": [ + [ + "dfdebe10dbf0e198" + ] + ] + }, + { + "id": "78e256083f59f66f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2120, + "wires": [ + [] + ] + }, + { + "id": "0f9141b401322374", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2240, + "wires": [ + [ + "9a56c087d941f1da" + ] + ] + }, + { + "id": "29f576be9e292232", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2240, + "wires": [ + [] + ] + }, + { + "id": "23e3099b34c4e475", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2280, + "wires": [ + [ + "0dfc86d90258f9bb" + ] + ] + }, + { + "id": "c4b5a38c5c1df3d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2280, + "wires": [ + [] + ] + }, + { + "id": "79a14162ac805fac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2320, + "wires": [ + [ + "1361134e9847f003" + ] + ] + }, + { + "id": "523717b0f218a5fd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2320, + "wires": [ + [] + ] + }, + { + "id": "f5cf780f3fa8997e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2160, + "wires": [ + [ + "b03e8b51187e88eb" + ] + ] + }, + { + "id": "11fd3363416433f9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2160, + "wires": [ + [] + ] + }, + { + "id": "02060b3f3b294563", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2200, + "wires": [ + [ + "543e1690693acbeb" + ] + ] + }, + { + "id": "e8b24efb0f30288e", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2200, + "wires": [ + [] + ] + }, + { + "id": "de1ad8b27b72a5ac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nvar steps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2360, + "wires": [ + [ + "c6642c7470d3820c" + ] + ] + }, + { + "id": "ed4d587cb4feb064", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2480, + "wires": [ + [ + "721b9680a3fa460e" + ] + ] + }, + { + "id": "5b02160c33605ae7", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2520, + "wires": [ + [ + "1610895f430b9aca" + ] + ] + }, + { + "id": "304c135ec09801e3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2560, + "wires": [ + [ + "277037c4716d85bf" + ] + ] + }, + { + "id": "a91dcbe0f9a2416a", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2400, + "wires": [ + [ + "6aae9d4fddf08cc0" + ] + ] + }, + { + "id": "6b2eb1cb95e573f9", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2440, + "wires": [ + [ + "10687d331a732790" + ] + ] + }, + { + "id": "eef89545ec0f6aa8", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2360, + "wires": [ + [] + ] + }, + { + "id": "b1b4678827d3a6dd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2480, + "wires": [ + [] + ] + }, + { + "id": "0f3367983bb8e159", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2520, + "wires": [ + [] + ] + }, + { + "id": "c9d2e31514def4fc", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2560, + "wires": [ + [] + ] + }, + { + "id": "e50492d1e18f43c6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2400, + "wires": [ + [] + ] + }, + { + "id": "af88b9da72917d62", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2440, + "wires": [ + [] + ] + }, + { + "id": "43fe948b3e7234e2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2660, + "wires": [ + [ + "2522f888dc58972f" + ] + ] + }, + { + "id": "5c752757090c49d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2660, + "wires": [ + [] + ] + }, + { + "id": "435681b3f7625a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2700, + "wires": [ + [ + "30e8df3d616512d8" + ] + ] + }, + { + "id": "a1769f0277834f6d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2700, + "wires": [ + [] + ] + }, + { + "id": "1de07c7d285cbaf3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2820, + "wires": [ + [ + "d855d926df89d65b" + ] + ] + }, + { + "id": "1a8b0ba21b4f3005", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2820, + "wires": [ + [] + ] + }, + { + "id": "ebc9e283468eda31", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2860, + "wires": [ + [ + "7617517dc8ba2859" + ] + ] + }, + { + "id": "dc8fc962ff7d594b", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2860, + "wires": [ + [] + ] + }, + { + "id": "60d641613527c736", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2900, + "wires": [ + [ + "cbaa23c34e10fae1" + ] + ] + }, + { + "id": "00e7836ccb3c4d0c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2900, + "wires": [ + [] + ] + }, + { + "id": "7f24c0c34a88ba04", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2940, + "wires": [ + [ + "f455fb39039617ae" + ] + ] + }, + { + "id": "3019576de193d9d6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2940, + "wires": [ + [] + ] + }, + { + "id": "77bb7dc529d63a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3060, + "wires": [ + [ + "e89f61dbe6a6cffe" + ] + ] + }, + { + "id": "885bc559fafec5f2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3060, + "wires": [ + [] + ] + }, + { + "id": "cc6dabe017a9c8a8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3380, + "wires": [ + [ + "eef25405472acfee" + ] + ] + }, + { + "id": "12d20f2274bcc511", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3380, + "wires": [ + [] + ] + }, + { + "id": "dcb9fed8122759fd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3100, + "wires": [ + [ + "70014da0b6ab6698" + ] + ] + }, + { + "id": "f70321c96bf81360", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3100, + "wires": [ + [] + ] + }, + { + "id": "013d2057c2347a62", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3140, + "wires": [ + [ + "2544963852c6881a" + ] + ] + }, + { + "id": "95e1603bbd06a69d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3140, + "wires": [ + [] + ] + }, + { + "id": "f88bbf11d5aa9a14", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3180, + "wires": [ + [ + "a1394401246eb735" + ] + ] + }, + { + "id": "a8f92ea6bf394640", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3180, + "wires": [ + [] + ] + }, + { + "id": "301af70731e096e5", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3220, + "wires": [ + [ + "f15ca4518b5f223e" + ] + ] + }, + { + "id": "06397bb46b3bb541", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3220, + "wires": [ + [] + ] + }, + { + "id": "0456a9ec4c236c9e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3260, + "wires": [ + [ + "49900bb9047dd965" + ] + ] + }, + { + "id": "687dcdc1ede11700", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3260, + "wires": [ + [] + ] + }, + { + "id": "09d37ba08ec0f163", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3300, + "wires": [ + [ + "5a90224dc998b417" + ] + ] + }, + { + "id": "37d954a4cf7e87ea", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3340, + "wires": [ + [ + "d2364ab09627fe94" + ] + ] + }, + { + "id": "e220740c0d38ccb0", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3300, + "wires": [ + [] + ] + }, + { + "id": "79d7e5a705ab813a", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3340, + "wires": [ + [] + ] + }, + { + "id": "22ef66b0e2058be2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 360, + "wires": [ + [ + "cb3437ec113e1b6f" + ] + ] + }, + { + "id": "9ce01c8ba97932c1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 400, + "wires": [ + [ + "60fd0adce1cfeb82" + ] + ] + }, + { + "id": "81356177176eebcf", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 480, + "wires": [ + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "b78346ca3ce70c68", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 320, + "wires": [ + [ + "f0d8dbcca76a1926" + ] + ] + }, + { + "id": "e95b86cbac1b03b9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "3e4c15d7b538f816", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 670, + "y": 1540, + "wires": [ + [ + "3bf622f344172721" + ] + ] + }, + { + "id": "0f0871baf322b6d0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1820, + "wires": [ + [ + "6ebd15c61a5ca891" + ] + ] + }, + { + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin_label", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1820, + "wires": [ + [] + ] + }, + { + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, + "wires": [ + [ + "acd10a4c99ee8063" + ] + ] + }, + { + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, + "wires": [ + [ + "031d7697768d0e77" + ] + ] + }, + { + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, + "wires": [ + [ + "be1954dd71d2c94c" + ] + ] + }, + { + "id": "edb1c8fae8b65c82", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1860, + "wires": [ + [ + "3ad0f0f206e4a873" + ] + ] + }, + { + "id": "031d7697768d0e77", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1860, + "wires": [ + [] + ] + }, + { + "id": "462a8f3ca75fc3c8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1900, + "wires": [ + [ + "3b6d759ed5be647f" + ] + ] + }, + { + "id": "be1954dd71d2c94c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1900, + "wires": [ + [] + ] + }, + { + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax_label", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart_label", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, + "wires": [ + [ + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88", + "53681e53353db898" + ] + ] + }, + { + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, + "y": 940, + "wires": [ + [ + "ded3086945a6d4b5", + "6ea3cdab41f20f92" + ] + ] + }, + { + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, + "wires": [ + [ + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd", + "a74d78a1d186a833" + ] + ] + }, + { + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2600, + "wires": [ + [ + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" + ] + ] + }, + { + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3060, + "wires": [ + [ + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8" + ] + ] + }, + { + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 680, + "wires": [ + [ + "53e6681d7254d484" + ] + ] + }, + { + "id": "53e6681d7254d484", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 270, + "y": 680, + "wires": [ + [ + "c11e79cfa7bc10b7" + ] + ] + }, + { + "id": "c11e79cfa7bc10b7", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 680, + "wires": [ + [ + "307782d10c1acdaf" + ] + ] + }, + { + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 680, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "cca3300a8f0daf4d", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 750, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "654bc70a18820828", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_contrast?contrast=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2780, + "wires": [ + [] + ] + }, + { + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_saturation?saturation=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2740, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2620, + "wires": [ + [ + "e612073aded01a8f" + ] + ] + }, + { + "id": "0d92559980944ae3", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, + "width": 3, + "height": 1, + "name": "delay_after", + "label": "Delay after", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2620, + "wires": [] + }, + { + "id": "6281b2e6e081104d", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2620, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2620, + "wires": [ + [] + ] + }, + { + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 560, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 560, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 210, + "y": 980, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 220, + "y": 1020, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 240, + "y": 1060, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] + }, + { + "id": "a7d233f984009e2e", + "type": "function", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 440, + "y": 980, + "wires": [ + [ + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" + ] + ] + }, + { + "id": "65518f3d4e3095e5", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 1", + "links": [ + "200d4b9951b6e066" + ], + "x": 85, + "y": 980, + "wires": [ + [ + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" + ] + ] + }, + { + "id": "9b851aa999e86fd7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", + "outputs": 1, + "x": 670, + "y": 980, + "wires": [ + [ + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" + ] + ] + }, + { + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 870, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, + "wires": [] + }, + { + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", + "links": [ + "592ec13d8f8923a9" + ], + "x": 815, + "y": 1020, + "wires": [] + }, + { + "id": "1eef47e0074545a9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, + "wires": [ + [ + "c994c779e4bad800", + "36890eb99a2ca1cf" + ], + [] + ] + }, + { + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, + "wires": [ + [ + "1eef47e0074545a9" + ] + ] + }, + { + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", + "name": "", + "x": 670, + "y": 1020, + "wires": [] + }, + { + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, + "wires": [] + }, + { + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 14, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, + "wires": [ + [ + "85ad07b8f973bbe2" + ] + ] + }, + { + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, + "wires": [ + [] + ] + }, + { + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, + "wires": [ + [ + "6b7245c3dcb694c8" + ] + ] + }, + { + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_endstop_enable", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, + "wires": [ + [ + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" + ] + ] + }, + { + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_endstop_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, + "wires": [ + [ + "253feafa5a2f8b1d" + ] + ] + }, + { + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, + "wires": [ + [] + ] + }, + { + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_endstop_enable_label", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 820, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 450, + "y": 1980, + "wires": [ + [ + "f036424d79645761", + "c7a41014cbbff864", + "69516440e3997111", + "e9a307a44d9f29f1" + ] + ] + }, + { + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, + "wires": [ + [ + "eefed04c25e3e4d6" + ] + ] + }, + { + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, + "wires": [ + [ + "2aaf7c7f0f0c146f" + ] + ] + }, + { + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", + "outputs": 1, + "x": 660, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3560, + "wires": [ + [ + "d0a1a4947a1137ca" + ] + ] + }, + { + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 540, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] + }, + { + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, + "wires": [ + [] + ] + }, + { + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3640, + "wires": [ + [ + "b5aba11033c5f952" + ] + ] + }, + { + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, + { + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "e98c1b83744bb863", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Delete Aborted", + "tooltip": "Delete aborted photosets", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 420, + "y": 520, + "wires": [ + [ + "7438a5bf5fcddec4" + ] + ] + }, + { + "id": "7438a5bf5fcddec4", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "delete_aborted", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('delete_aborted'):\n save('delete_aborted', state)\n", + "outputs": 1, + "x": 600, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "53681e53353db898", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'delete_aborted'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 520, + "wires": [ + [ + "e98c1b83744bb863" + ] + ] + }, + { + "id": "48386fdb54980ec7", + "type": "comment", + "z": "e43a27722b508115", + "name": "Shield", + "info": "", + "x": 90, + "y": 3760, + "wires": [] + }, + { + "id": "fbc5fc2e65311f8b", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 3", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3840, + "wires": [ + [ + "5618e266f6966ae6" + ] + ] + }, + { + "id": "5618e266f6966ae6", + "type": "function", + "z": "e43a27722b508115", + "name": "loadl", + "func": "var file = 'shield_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 170, + "y": 3840, + "wires": [ + [ + "c97113d841391e40" + ] + ] + }, + { + "id": "c97113d841391e40", + "type": "ui_dropdown", + "z": "e43a27722b508115", + "name": "", + "label": "Shield Type", + "tooltip": "", + "place": "Select option", + "group": "0b244f698c7ac9a2", + "order": 0, + "width": 0, + "height": 0, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "Green", + "value": "green", + "type": "str" + }, + { + "label": "Black", + "value": "black", + "type": "str" + } + ], + "payload": "", + "topic": "payload", + "topicType": "msg", + "className": "", + "x": 310, + "y": 3840, + "wires": [ + [ + "2b639346c1b56578" + ] + ] + }, + { + "id": "2b639346c1b56578", + "type": "function", + "z": "e43a27722b508115", + "name": "function 2", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'shield_type';\nconst current_shield = fs.readFileSync(filepath + file, 'utf8');\n\nvar current_choice = msg.payload\n\nif (current_choice != current_shield) {\n \n switch (current_choice) {\n case \"green\":\n fs.writeFile(filepath + 'pin_external', String(10), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(17), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(9), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(11), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(14), err => {\n if (err) {\n return\n }\n });\n break;\n case \"black\":\n fs.writeFile(filepath + 'pin_external', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(24), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(22), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(17), err => {\n if (err) {\n return\n }\n });\n break;\n case \"custom\":\n break;\n }\n\n fs.writeFile(filepath + file, current_choice, err => {\n if (err) {\n return\n }\n });\n}\n\nmsg.status = 'The new ' + current_choice + ' shield has been configured'\nmsg.topic = msg.status\nmsg.payload = 'Do you want to reboot now to apply the changes?'\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 460, + "y": 3840, + "wires": [ + [ + "137f032887544d74" + ] + ] + }, + { + "id": "137f032887544d74", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": false, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Reboot", + "x": 600, + "y": 3840, + "wires": [ + [ + "d2db49796fe0da79", + "d0d6820224b0ab0f" + ] + ] + }, + { + "id": "d2db49796fe0da79", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "print(msg['payload'])\nreturn msg", + "outputs": 1, + "x": 790, + "y": 3840, + "wires": [ + [] + ] + }, + { + "id": "d0d6820224b0ab0f", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 6", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 780, + "y": 3720, + "wires": [] + }, + { + "id": "a74d78a1d186a833", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotate_tt_first'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1760, + "wires": [ + [ + "4e1b38e60f4179b0" + ] + ] + }, + { + "id": "4e1b38e60f4179b0", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotate_tt_first", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 3, + "width": "3", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 430, + "y": 1760, + "wires": [ + [ + "0e14711b77c43c23" + ] + ] + }, + { + "id": "0e14711b77c43c23", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotate_tt_first'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1760, + "wires": [ + [] + ] + }, + { + "id": "b1d13cc1ebec82d7", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 2, + "width": 3, + "height": 1, + "name": "rotate_tt_first_label", + "label": "Rotate turntable first", + "format": "", + "layout": "row-left", + "className": "", + "x": 790, + "y": 1760, + "wires": [] + }, + { + "id": "d9d7acf381c002cf", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "restart interface", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('service flask restart')\nos.system('service nodered restart')\n", + "outputs": 1, + "x": 300, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "acfcc56da7ec7880", + "type": "link in", + "z": "e43a27722b508115", + "name": "restart interface", + "links": [ + "fe3a855fee9e28c6" + ], + "x": 155, + "y": 600, + "wires": [ + [ + "d9d7acf381c002cf" + ] + ] + }, + { + "id": "c7a41014cbbff864", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_pushed'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2060, + "wires": [ + [ + "5712cdb7d571f18c" + ] + ] + }, + { + "id": "5712cdb7d571f18c", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_endstop_pushed", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 2060, + "wires": [ + [ + "168334311f605afd" + ] + ] + }, + { + "id": "168334311f605afd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_pushed'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2060, + "wires": [ + [] + ] + }, + { + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, + "width": 3, + "height": 1, + "name": "rotor_endstop_angle_label", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 820, + "y": 2020, + "wires": [] + }, + { + "id": "e9a307a44d9f29f1", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "rotor_endstop_pushed_label", + "label": "Endstop reverse", + "format": "", + "layout": "row-left", + "className": "", + "x": 820, + "y": 2060, + "wires": [] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'stable'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, + "wires": [ + [ + "e23c514008cad1a1" + ] + ] + }, + { + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] + }, + { + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, + "wires": [ + [ + "4ce127c61c3c5966", + "beacc3dc5398fa79" + ] + ] + }, + { + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", + "outputs": 1, + "x": 290, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "beacc3dc5398fa79", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "e23c514008cad1a1", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 480, + "y": 140, + "wires": [] + }, + { + "id": "b0629875a30ae1d7", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nopenscan_version = load_str('openscan_version')\nopenscan_branch = load_str('openscan_branch')\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/' + openscan_version + '/update/' + openscan_version\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + '/update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\nmsg['url'] = url\nmsg['openscan_branch'] = openscan_branch\nmsg['openscan_version'] = openscan_version\n\nreturn msg, msg", + "outputs": 2, + "x": 390, + "y": 540, + "wires": [ + [ + "1bbe2d769f42c313" + ], + [ + "fefe45404bdb19c4", + "44573d9223b2a75d" + ] + ] + }, + { + "id": "c7b6d05a62172432", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Status:", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 210, + "y": 400, + "wires": [] + }, + { + "id": "fefe45404bdb19c4", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "check files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nopenscan_version = msg['openscan_version']\nopenscan_branch = msg['openscan_branch']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = msg['url']\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[openscan_branch]:\n filepath = msg[openscan_branch][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[openscan_branch][i]['filesize2'] = filesize\n if filesize == msg[openscan_branch][i]['filesize']:\n msg[openscan_branch][i]['update'] = False\n continue\n msg[openscan_branch][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "outputs": 1, + "x": 550, + "y": 560, + "wires": [ + [ + "1bbe2d769f42c313", + "ae92a328af306ebb" + ] + ] + }, + { + "id": "d0104e0163745993", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 115, + "y": 440, + "wires": [ + [ + "ec30638407332e43", + "49f1ecb29a3f84f4" + ] + ] + }, + { + "id": "ec30638407332e43", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadS", + "func": "var file = 'openscan_branch'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 440, + "wires": [ + [ + "2852023f3aa8db10" + ] + ] + }, + { + "id": "2852023f3aa8db10", + "type": "ui_dropdown", + "z": "a5557543ccff5889", + "name": "", + "label": "", + "tooltip": "", + "place": "Select option", + "group": "ddbd496e.93a288", + "order": 4, + "width": 2, + "height": 1, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "stable", + "value": "stable", + "type": "str" + }, + { + "label": "beta", + "value": "beta", + "type": "str" + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" + } + ], + "payload": "", + "topic": "topic", + "topicType": "msg", + "className": "", + "x": 390, + "y": 440, + "wires": [ + [ + "1e10b387ee30c486" + ] + ] + }, + { + "id": "1e10b387ee30c486", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'openscan_branch'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 520, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "274129c51b0b87ef", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 3, + "width": 4, + "height": 1, + "name": "", + "label": "Branch: ", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 650, + "y": 440, + "wires": [] + }, + { + "id": "51cd8c8643e6b46a", + "type": "ui_switch", + "z": "a5557543ccff5889", + "name": "", + "label": "Auto-check update availability", + "tooltip": "", + "group": "ddbd496e.93a288", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 449, + "y": 491, + "wires": [ + [ + "1ab4c6b4b232a022" + ] + ] + }, + { + "id": "1ab4c6b4b232a022", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 649, + "y": 491, + "wires": [ + [] + ] + }, + { + "id": "ae92a328af306ebb", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "NO", + "cancel": "YES", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 710, + "y": 560, + "wires": [ + [ + "2de63e8e3ae5fb0c", + "929281fef53e09f8" + ] + ] + }, + { + "id": "cbd0afc4aa7b302a", + "type": "link in", + "z": "a5557543ccff5889", + "name": "update status", + "links": [ + "1bbe2d769f42c313", + "42061b28cff81f99" + ], + "x": 115, + "y": 400, + "wires": [ + [ + "c7b6d05a62172432", + "c94623ddd9d95f78" + ] + ] + }, + { + "id": "1bbe2d769f42c313", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 665, + "y": 520, + "wires": [] + }, + { + "id": "7cf60615d93e696b", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Check Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 180, + "y": 560, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "2de63e8e3ae5fb0c", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "download files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\nopenscan_version = msg['openscan_version']\nopenscan_branch = msg['openscan_branch']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = msg['url']\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[openscan_branch]:\n if msg[openscan_branch][i]['update'] == False:\n continue\n \n filepath = msg[openscan_branch][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + '/' + msg[openscan_branch][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[openscan_branch][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[openscan_branch][i]['dst'])\n \n if msg[openscan_branch][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "outputs": 1, + "x": 880, + "y": 560, + "wires": [ + [ + "42061b28cff81f99", + "fe3a855fee9e28c6" + ] + ] + }, + { + "id": "929281fef53e09f8", + "type": "function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 850, + "y": 520, + "wires": [ + [ + "42061b28cff81f99" + ] + ] + }, + { + "id": "42061b28cff81f99", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 995, + "y": 520, + "wires": [] + }, + { + "id": "49f1ecb29a3f84f4", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 480, + "wires": [ + [ + "b0629875a30ae1d7", + "51cd8c8643e6b46a" + ] + ] + }, + { + "id": "fe3a855fee9e28c6", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "9bb0adbd716ce347", + "01c882fcc51b349c", + "acfcc56da7ec7880" + ], + "x": 995, + "y": 560, + "wires": [] + }, + { + "id": "5e7d5e4335d37794", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 95, + "y": 700, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "2bb5fe78e09fec8a", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", + "outputs": 1, + "x": 210, + "y": 700, + "wires": [ + [ + "dbc77052ac950624", + "d97c3068ef5fef96", + "73a3b828f862312b", + "901e31453b2bdff8", + "f983854748ee4763", + "5347c7c517f5e8c7", + "3a5016f7003cd72c", + "6d720c4a4ecd9475", + "6438b7d060a70d81" + ] + ] + }, + { + "id": "d97c3068ef5fef96", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "OS:", + "format": "{{msg.os}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 740, + "wires": [] + }, + { + "id": "73a3b828f862312b", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 8, + "width": 0, + "height": 0, + "name": "", + "label": "Flask:", + "format": "{{msg.flask}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 780, + "wires": [] + }, + { + "id": "dbc77052ac950624", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Device:", + "format": "{{msg.device}}", + "layout": "row-spread", + "className": "", + "x": 500, + "y": 700, + "wires": [] + }, + { + "id": "3f42560297fe6978", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "name": "Download LOG", + "order": 9, + "width": 6, + "height": 1, + "format": "\n
Download error log\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 180, + "y": 1060, + "wires": [ + [] + ] + }, + { + "id": "c94623ddd9d95f78", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", + "outputs": 1, + "x": 210, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "39a502b38837273d", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "1e7457ea9c2c5e09" + ], + "x": 245, + "y": 600, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "901e31453b2bdff8", + "type": "delay", + "z": "a5557543ccff5889", + "name": "", + "pauseType": "delay", + "timeout": "10", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 220, + "y": 740, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "f983854748ee4763", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "", + "format": "{{msg.osdate}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 820, + "wires": [] + }, + { + "id": "5347c7c517f5e8c7", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "CPU temp:", + "format": "{{msg.temp}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 860, + "wires": [] + }, + { + "id": "3a5016f7003cd72c", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "CPU memory:", + "format": "{{msg.cpu}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 900, + "wires": [] + }, + { + "id": "6d720c4a4ecd9475", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 6, + "width": 0, + "height": 0, + "name": "", + "label": "Swap memory:", + "format": "{{msg.swap}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 940, + "wires": [] + }, + { + "id": "6438b7d060a70d81", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 7, + "width": 0, + "height": 0, + "name": "", + "label": "Diskspace:", + "format": "{{msg.diskspace}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 980, + "wires": [] + }, + { + "id": "8d012912f302be85", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 7, + "width": 6, + "height": 1, + "passthru": false, + "label": "Show Details/Changelog", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 210, + "y": 640, + "wires": [ + [ + "5242607a723cc628" + ] + ] + }, + { + "id": "5242607a723cc628", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "Changelog", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "outputs": 1, + "x": 430, + "y": 640, + "wires": [ + [ + "573722197b15bf84" + ] + ] + }, + { + "id": "573722197b15bf84", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 640, + "wires": [ + [] + ] + }, + { + "id": "28cab3989dcf898b", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "name": "Download Config", + "order": 9, + "width": 0, + "height": 0, + "format": "\n\n
Download Config\n
\n
\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 530, + "y": 1020, + "wires": [ + [] + ] + }, + { + "id": "c5268070.c55a3", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "name": "Upload Btn", + "order": 8, + "width": "3", + "height": 1, + "format": "\n \n
Upload Config
\n
\n\n \n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 510, + "y": 1060, + "wires": [ + [ + "f92f5fe65eaea996" + ] + ] + }, + { + "id": "5e18b80e617a3db8", + "type": "debug", + "z": "a5557543ccff5889", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 790, + "y": 1000, + "wires": [] + }, + { + "id": "44573d9223b2a75d", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 8", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 720, + "y": 380, + "wires": [] + }, + { + "id": "f92f5fe65eaea996", + "type": "file", + "z": "a5557543ccff5889", + "name": "Save Settings", + "filename": "/home/pi/OpenScan/tmp2/upload.zip", + "filenameType": "str", + "appendNewline": false, + "createDir": false, + "overwriteFile": "true", + "encoding": "binary", + "x": 700, + "y": 1060, + "wires": [ + [] + ] + }, + { + "id": "c4f91df3.caef7", + "type": "http in", + "z": "a5557543ccff5889", + "name": "", + "url": "/files", + "method": "post", + "upload": true, + "swaggerDoc": "", + "x": 240, + "y": 1280, + "wires": [ + [ + "cc5a37cf.86c6d8", + "c14febc0.522db8" + ] + ] + }, + { + "id": "ef0aaf76.2236e", + "type": "http response", + "z": "a5557543ccff5889", + "name": "", + "statusCode": "", + "headers": {}, + "x": 590, + "y": 1280, + "wires": [] + }, + { + "id": "cc5a37cf.86c6d8", + "type": "debug", + "z": "a5557543ccff5889", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "req", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 400, + "y": 1320, + "wires": [] + }, + { + "id": "6a156025.b1c9f", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 240, + "y": 1380, + "wires": [ + [ + "fd62708f.a560a" + ] + ] + }, + { + "id": "9c0b2081.b1ac6", + "type": "function", + "z": "a5557543ccff5889", + "name": "Format the header and payload", + "func": "msg.headers = {\n \"Content-Type\": \"multipart/form-data; boundary=------------------------d74496d66958873e\"\n}\n\n\nmsg.payload = '--------------------------d74496d66958873e\\r\\n'+\n'Content-Disposition: form-data; name=\"select\"\\r\\n'+\n'\\r\\n'+\n'true\\r\\n'+\n'--------------------------d74496d66958873e\\r\\n'+\n'Content-Disposition: form-data; name=\"print\"\\r\\n'+\n'\\r\\n'+\n'true\\r\\n'+\n'--------------------------d74496d66958873e\\r\\n'+\n'Content-Disposition: form-data; name=\"file\"; filename=\"'+msg.filename+'\"\\r\\n'+\n'Content-Type: application/octet-stream\\r\\n'+\n'\\r\\n'+\nmsg.payload+'\\r\\n'+\n'--------------------------d74496d66958873e--\\r\\n';\n\n\nreturn msg;", + "outputs": 1, + "noerr": 0, + "x": 370, + "y": 1440, + "wires": [ + [ + "85c748e8.2d1f88" + ] + ] + }, + { + "id": "85c748e8.2d1f88", + "type": "http request", + "z": "a5557543ccff5889", + "name": "", + "method": "POST", + "ret": "txt", + "paytoqs": false, + "url": "http://localhost:1880/files", + "tls": "", + "proxy": "", + "x": 610, + "y": 1440, + "wires": [ + [ + "a4810d7a.f652a" + ] + ] + }, + { + "id": "a4810d7a.f652a", + "type": "debug", + "z": "a5557543ccff5889", + "name": "", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "x": 790, + "y": 1440, + "wires": [] + }, + { + "id": "c14febc0.522db8", + "type": "change", + "z": "a5557543ccff5889", + "name": "", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "okay", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 1280, + "wires": [ + [ + "ef0aaf76.2236e" + ] + ] + }, + { + "id": "fd62708f.a560a", + "type": "file in", + "z": "a5557543ccff5889", + "name": "", + "filename": "/tmp/file.txt", + "filenameType": "str", + "format": "", + "chunk": false, + "sendError": false, + "allProps": false, + "x": 420, + "y": 1380, + "wires": [ + [ + "9c0b2081.b1ac6" + ] + ] + }, + { + "id": "9b3e6a06c82a0f52", + "type": "link in", + "z": "87715429b0b1c9a3", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 55, + "y": 120, + "wires": [ + [ + "f128ca405d1e1e4d", + "07d7ce3dab5f1c11" + ] + ] + }, + { + "id": "cd0dc08fcb5968c8", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Successful Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 100, + "wires": [] + }, + { + "id": "f128ca405d1e1e4d", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics*.json|grep -i \\\"aborted\\\":false|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Successful Scans", + "x": 210, + "y": 120, + "wires": [ + [ + "cd0dc08fcb5968c8" + ], + [], + [] + ] + }, + { + "id": "b91b4d65f2090793", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Aborted Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 400, + "y": 160, + "wires": [] + }, + { + "id": "07d7ce3dab5f1c11", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics*.json|grep -i \\\"aborted\\\":true|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Aborted Scans", + "x": 200, + "y": 180, + "wires": [ + [ + "b91b4d65f2090793" + ], + [], + [] + ] + }, + { + "id": "5b3aa9a71591ba34", + "type": "comment", + "z": "87715429b0b1c9a3", + "name": "Statistics", + "info": "", + "x": 100, + "y": 40, + "wires": [] + } +] \ No newline at end of file diff --git a/update/2024-1o/meanwhile/settings.js b/update/2024-1o/meanwhile/settings.js new file mode 100644 index 0000000..b707922 --- /dev/null +++ b/update/2024-1o/meanwhile/settings.js @@ -0,0 +1,516 @@ +/** + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT + * + * It can contain any valid JavaScript code that will get run when Node-RED + * is started. + * + * Lines that start with // are commented out. + * Each entry should be separated from the entries above and below by a comma ',' + * + * For more information about individual settings, refer to the documentation: + * https://nodered.org/docs/user-guide/runtime/configuration + * + * The settings are split into the following sections: + * - Flow File and User Directory Settings + * - Security + * - Server Settings + * - Runtime Settings + * - Editor Settings + * - Node Settings + * + **/ +process.env.HOSTNAME = require('os').hostname(); + +module.exports = { + +/******************************************************************************* + * Flow File and User Directory Settings + * - flowFile + * - credentialSecret + * - flowFilePretty + * - userDir + * - nodesDir + ******************************************************************************/ + + /** The file containing the flows. If not set, defaults to flows_.json **/ + flowFile: "flows.json", + + /** By default, credentials are encrypted in storage using a generated key. To + * specify your own secret, set the following property. + * If you want to disable encryption of credentials, set this property to false. + * Note: once you set this property, do not change it - doing so will prevent + * node-red from being able to decrypt your existing credentials and they will be + * lost. + */ + credentialSecret: false, + + /** By default, the flow JSON will be formatted over multiple lines making + * it easier to compare changes when using version control. + * To disable pretty-printing of the JSON set the following property to false. + */ + flowFilePretty: true, + + /** By default, all user data is stored in a directory called `.node-red` under + * the user's home directory. To use a different location, the following + * property can be used + */ + //userDir: '/home/nol/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + + /** Node-RED scans the `nodes` directory in the userDir to find local node files. + * The following property can be used to specify an additional directory to scan. + */ + //nodesDir: '/home/nol/.node-red/nodes', + +/******************************************************************************* + * Security + * - adminAuth + * - https + * - httpsRefreshInterval + * - requireHttps + * - httpNodeAuth + * - httpStaticAuth + ******************************************************************************/ + + /** To password protect the Node-RED editor and admin API, the following + * property can be used. See http://nodered.org/docs/security.html for details. + */ + //adminAuth: { + // type: "credentials", + // users: [{ + // username: "admin", + // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", + // permissions: "*" + // }] + //}, + + /** The following property can be used to enable HTTPS + * This property can be either an object, containing both a (private) key + * and a (public) certificate, or a function that returns such an object. + * See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener + * for details of its contents. + */ + + /** Option 1: static object */ + //https: { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + //}, + + /** Option 2: function that returns the HTTP configuration object */ + // https: function() { + // // This function should return the options object, or a Promise + // // that resolves to the options object + // return { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + // } + // }, + + /** If the `https` setting is a function, the following setting can be used + * to set how often, in hours, the function will be called. That can be used + * to refresh any certificates. + */ + //httpsRefreshInterval : 12, + + /** The following property can be used to cause insecure HTTP connections to + * be redirected to HTTPS. + */ + //requireHttps: true, + + /** To password protect the node-defined HTTP endpoints (httpNodeRoot), + * including node-red-dashboard, or the static content (httpStatic), the + * following properties can be used. + * The `pass` field is a bcrypt hash of the password. + * See http://nodered.org/docs/security.html#generating-the-password-hash + */ + //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + +/******************************************************************************* + * Server Settings + * - uiPort + * - uiHost + * - apiMaxLength + * - httpServerOptions + * - httpAdminRoot + * - httpAdminMiddleware + * - httpNodeRoot + * - httpNodeCors + * - httpNodeMiddleware + * - httpStatic + * - httpStaticRoot + ******************************************************************************/ + + /** the tcp port that the Node-RED web server is listening on */ + uiPort: process.env.PORT || 80, + + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. + * To listen on all IPv6 addresses, set uiHost to "::", + * The following property can be used to listen on a specific interface. For + * example, the following would only allow connections from the local machine. + */ + //uiHost: "127.0.0.1", + + /** The maximum size of HTTP request that will be accepted by the runtime api. + * Default: 5mb + */ + //apiMaxLength: '5mb', + + /** The following property can be used to pass custom options to the Express.js + * server used by Node-RED. For a full list of available options, refer + * to http://expressjs.com/en/api.html#app.settings.table + */ + //httpServerOptions: { }, + + /** By default, the Node-RED UI is available at http://localhost:1880/ + * The following property can be used to specify a different root path. + * If set to false, this is disabled. + */ + httpAdminRoot: '/editor', + + /** The following property can be used to add a custom middleware function + * in front of all admin http routes. For example, to set custom http + * headers. It can be a single function or an array of middleware functions. + */ + // httpAdminMiddleware: function(req,res,next) { + // // Set the X-Frame-Options header to limit where the editor + // // can be embedded + // //res.set('X-Frame-Options', 'sameorigin'); + // next(); + // }, + + + /** Some nodes, such as HTTP In, can be used to listen for incoming http requests. + * By default, these are served relative to '/'. The following property + * can be used to specifiy a different root path. If set to false, this is + * disabled. + */ + //httpNodeRoot: '/red-nodes', + + /** The following property can be used to configure cross-origin resource sharing + * in the HTTP nodes. + * See https://github.com/troygoode/node-cors#configuration-options for + * details on its contents. The following is a basic permissive set of options: + */ + //httpNodeCors: { + // origin: "*", + // methods: "GET,PUT,POST,DELETE" + //}, + + /** If you need to set an http proxy please set an environment variable + * called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. + * For example - http_proxy=http://myproxy.com:8080 + * (Setting it here will have no effect) + * You may also specify no_proxy (or NO_PROXY) to supply a comma separated + * list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk + */ + + /** The following property can be used to add a custom middleware function + * in front of all http in nodes. This allows custom authentication to be + * applied to all http in nodes, or any other sort of common request processing. + * It can be a single function or an array of middleware functions. + */ + //httpNodeMiddleware: function(req,res,next) { + // // Handle/reject the request, or pass it on to the http in node by calling next(); + // // Optionally skip our rawBodyParser by setting this to true; + // //req.skipRawBodyParser = true; + // next(); + //}, + + /** When httpAdminRoot is used to move the UI to a different root path, the + * following property can be used to identify a directory of static content + * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot + */ + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + httpStatic: [ + {path: '/home/pi/OpenScan/tmp2/', root: "/tmp2/"}, + {path: '/home/pi/OpenScan/scans/', root: "/scans/"} + ], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + +/******************************************************************************* + * Runtime Settings + * - lang + * - logging + * - contextStorage + * - exportGlobalContextKeys + * - externalModules + ******************************************************************************/ + + /** Uncomment the following to run node-red in your preferred language. + * Available languages include: en-US (default), ja, de, zh-CN, zh-TW, ru, ko + * Some languages are more complete than others. + */ + // lang: "de", + + /** Configure the logging output */ + logging: { + /** Only console logging is currently supported */ + console: { + /** Level of logging to be recorded. Options are: + * fatal - only those errors which make the application unusable should be recorded + * error - record errors which are deemed fatal for a particular request + fatal errors + * warn - record problems which are non fatal + errors + fatal errors + * info - record information about the general running of the application + warn + error + fatal errors + * debug - record information which is more verbose than info + info + warn + error + fatal errors + * trace - record very detailed logging + debug + info + warn + error + fatal errors + * off - turn off all logging (doesn't affect metrics or audit) + */ + level: "info", + /** Whether or not to include metric events in the log output */ + metrics: false, + /** Whether or not to include audit events in the log output */ + audit: false + } + }, + + /** Context Storage + * The following property can be used to enable context storage. The configuration + * provided here will enable file-based context that flushes to disk every 30 seconds. + * Refer to the documentation for further options: https://nodered.org/docs/api/context/ + */ + //contextStorage: { + // default: { + // module:"localfilesystem" + // }, + //}, + + /** `global.keys()` returns a list of all properties set in global context. + * This allows them to be displayed in the Context Sidebar within the editor. + * In some circumstances it is not desirable to expose them to the editor. The + * following property can be used to hide any property set in `functionGlobalContext` + * from being list by `global.keys()`. + * By default, the property is set to false to avoid accidental exposure of + * their values. Setting this to true will cause the keys to be listed. + */ + exportGlobalContextKeys: false, + + /** Configure how the runtime will handle external npm modules. + * This covers: + * - whether the editor will allow new node modules to be installed + * - whether nodes, such as the Function node are allowed to have their + * own dynamically configured dependencies. + * The allow/denyList options can be used to limit what modules the runtime + * will install/load. It can use '*' as a wildcard that matches anything. + */ + externalModules: { + // autoInstall: false, /** Whether the runtime will attempt to automatically install missing modules */ + // autoInstallRetry: 30, /** Interval, in seconds, between reinstall attempts */ + // palette: { /** Configuration for the Palette Manager */ + // allowInstall: true, /** Enable the Palette Manager in the editor */ + // allowUpload: true, /** Allow module tgz files to be uploaded and installed */ + // allowList: [], + // denyList: [] + // }, + // modules: { /** Configuration for node-specified modules */ + // allowInstall: true, + // allowList: [], + // denyList: [] + // } + }, + + +/******************************************************************************* + * Editor Settings + * - disableEditor + * - editorTheme + ******************************************************************************/ + + /** The following property can be used to disable the editor. The admin API + * is not affected by this option. To disable both the editor and the admin + * API, use either the httpRoot or httpAdminRoot properties + */ + //disableEditor: false, + + /** Customising the editor + * See https://nodered.org/docs/user-guide/runtime/configuration#editor-themes + * for all available options. + */ + editorTheme: { + /** The following property can be used to set a custom theme for the editor. + * See https://github.com/node-red-contrib-themes/theme-collection for + * a collection of themes to chose from. + */ + //theme: "", + palette: { + /** The following property can be used to order the categories in the editor + * palette. If a node's category is not in the list, the category will get + * added to the end of the palette. + * If not set, the following default order is used: + */ + //categories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], + }, + projects: { + /** To enable the Projects feature, set this value to true */ + enabled: false, + workflow: { + /** Set the default projects workflow mode. + * - manual - you must manually commit changes + * - auto - changes are automatically committed + * This can be overridden per-user from the 'Git config' + * section of 'User Settings' within the editor + */ + mode: "manual" + } + }, + codeEditor: { + /** Select the text editor component used by the editor. + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired + */ + lib: "monaco", + options: { + /** The follow options only apply if the editor is set to "monaco" + * + * theme - must match the file name of a theme in + * packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/theme + * e.g. "tomorrow-night", "upstream-sunburst", "github", "my-theme" + */ + theme: "vs", + /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html + */ + //fontSize: 14, + //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", + //fontLigatures: true, + } + } + }, + +/******************************************************************************* + * Node Settings + * - fileWorkingDirectory + * - functionGlobalContext + * - functionExternalModules + * - nodeMessageBufferMaxLength + * - ui (for use with Node-RED Dashboard) + * - debugUseColors + * - debugMaxLength + * - execMaxBufferSize + * - httpRequestTimeout + * - mqttReconnectTime + * - serialReconnectTime + * - socketReconnectTime + * - socketTimeout + * - tcpMsgQueueSize + * - inboundWebSocketTimeout + * - tlsConfigDisableLocalFiles + * - webSocketNodeVerifyClient + ******************************************************************************/ + + /** The working directory to handle relative file paths from within the File nodes + * defaults to the working directory of the Node-RED process. + */ + //fileWorkingDirectory: "", + + /** Allow the Function node to load additional npm modules directly */ + functionExternalModules: true, + + /** The following property can be used to set predefined values in Global Context. + * This allows extra node modules to be made available with in Function node. + * For example, the following: + * functionGlobalContext: { os:require('os') } + * will allow the `os` module to be accessed in a Function node using: + * global.get("os") + */ +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, + /** The maximum number of messages nodes will buffer internally as part of their + * operation. This applies across a range of nodes that operate on message sequences. + * defaults to no limit. A value of 0 also means no limit is applied. + */ + //nodeMessageBufferMaxLength: 0, + + /** If you installed the optional node-red-dashboard you can set it's path + * relative to httpNodeRoot + * Other optional properties include + * readOnly:{boolean}, + * middleware:{function or array}, (req,res,next) - http middleware + * ioMiddleware:{function or array}, (socket,next) - socket.io middleware + */ + ui: { path: "" }, + + /** Colourise the console output of the debug node */ + //debugUseColors: true, + + /** The maximum length, in characters, of any message sent to the debug sidebar tab */ + debugMaxLength: 1000, + + /** Maximum buffer size for the exec node. Defaults to 10Mb */ + //execMaxBufferSize: 10000000, + + /** Timeout in milliseconds for HTTP request connections. Defaults to 120s */ + //httpRequestTimeout: 120000, + + /** Retry time in milliseconds for MQTT connections */ + mqttReconnectTime: 15000, + + /** Retry time in milliseconds for Serial port connections */ + serialReconnectTime: 15000, + + /** Retry time in milliseconds for TCP socket connections */ + //socketReconnectTime: 10000, + + /** Timeout in milliseconds for TCP server socket connections. Defaults to no timeout */ + //socketTimeout: 120000, + + /** Maximum number of messages to wait in queue while attempting to connect to TCP socket + * defaults to 1000 + */ + //tcpMsgQueueSize: 2000, + + /** Timeout in milliseconds for inbound WebSocket connections that do not + * match any configured node. Defaults to 5000 + */ + //inboundWebSocketTimeout: 5000, + + /** To disable the option for using local files for storing keys and + * certificates in the TLS configuration node, set this to true. + */ + //tlsConfigDisableLocalFiles: true, + + /** The following property can be used to verify websocket connection attempts. + * This allows, for example, the HTTP request headers to be checked to ensure + * they include valid authentication information. + */ + //webSocketNodeVerifyClient: function(info) { + // /** 'info' has three properties: + // * - origin : the value in the Origin header + // * - req : the HTTP request + // * - secure : true if req.connection.authorized or req.connection.encrypted is set + // * + // * The function should return true if the connection should be accepted, false otherwise. + // * + // * Alternatively, if this function is defined to accept a second argument, callback, + // * it can be used to verify the client asynchronously. + // * The callback takes three arguments: + // * - result : boolean, whether to accept the connection or not + // * - code : if result is false, the HTTP error status to return + // * - reason: if result is false, the HTTP reason string to return + // */ + //}, +} diff --git a/update/2024-1o/scripts/expand_root.sh b/update/2024-1o/scripts/expand_root.sh new file mode 100755 index 0000000..5f57a36 --- /dev/null +++ b/update/2024-1o/scripts/expand_root.sh @@ -0,0 +1,7 @@ +#!/bin/bash +if [ "$1" = "-f" ] || test -f "/boot/expand_root"; then + echo "expanding root partition" + raspi-config --expand-rootfs + rm -fr /boot/expand_root + shutdown -r now +fi diff --git a/update/2024-1o/scripts/startup.sh b/update/2024-1o/scripts/startup.sh new file mode 100755 index 0000000..bdaad1d --- /dev/null +++ b/update/2024-1o/scripts/startup.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +settings_folder="/home/pi/OpenScan/settings" + +# Generate an unique UUID that identifies that OpenScan + +if [ ! -f $settings_folder/openscan_uuid ]; then + echo $(cat /proc/sys/kernel/random/uuid) > $settings_folder/openscan_uuid +fi +echo `cat /proc/cpuinfo|grep Model|cut -d: -f2|awk '{$1=$1};1'` > $settings_folder/architecture +echo `libcamera-still --list-cameras|head -3|tail -1|cut -d: -f2|cut -d[ -f1|awk '{$1=$1};1'` > $settings_folder/camera diff --git a/update/2024-1o/stable/OpenScan.py b/update/2024-1o/stable/OpenScan.py new file mode 100644 index 0000000..cbce61c --- /dev/null +++ b/update/2024-1o/stable/OpenScan.py @@ -0,0 +1,317 @@ +basepath = '/home/pi/OpenScan/' +from os.path import isfile +import os + +def load_bool(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + if value == '1' or value == 'True' or value =='true': + value = True + else: + value = False + return value + +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + return True + +def load_str(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + return value + +def load_int(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = int(file.read().replace('\n','')) + return value + +def load_float(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = float(file.read().replace('\n','')) + return value + +def save(name, value): + filename = basepath+'settings/'+name + with open(filename, 'w+') as file: + file.write(str(value)) + return + +def OpenScanCloud(cmd, msg): + from requests import get + osc_user = 'openscan' + osc_pw = 'free' + osc_server = 'http://openscanfeedback.dnsuser.de:1334/' + + try: + r = get(osc_server + cmd, auth=(osc_user, osc_pw), params=msg) + except: + r = type('obj', (object,), {'status_code' : 404, 'text':None}) + return r + +def camera(cmd, msg = {}): + from requests import get + flask = 'http://127.0.0.1:1312/' + try: + r = get(flask + cmd, params=msg) + return r.status_code + except: + return 400 + +def motorrun(motor,angle,ES_enable=False,ES_start_state = True): + #motor can be "rotor", "tt" or "extra" + import RPi.GPIO as GPIO + from time import sleep + from math import cos + msg = {'cmd':'set'} + + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + + spr = load_int(motor + '_stepsperrotation') + dirpin = load_int('pin_' + motor + '_dir') + steppin = load_int('pin_' + motor +'_step') + ES_pin = load_int('pin_' + motor + '_endstop') + dir = load_int(motor + '_dir') + ramp = load_int(motor + '_accramp') + acc = load_float(motor + '_acc') + if motor != 'tt': + ES_pin = load_int('pin_' + motor + '_endstop') + else: + ES_pin = '33' + delay_init = load_float(motor + '_delay') + delay = delay_init + + step_count=int(angle*spr/360) * dir + GPIO.setup(dirpin, GPIO.OUT) + GPIO.setup(steppin, GPIO.OUT) + if motor != 'tt': + GPIO.setup(ES_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP) + + if (step_count>0): + GPIO.output(dirpin, GPIO.HIGH) + if(step_count<0): + GPIO.output(dirpin, GPIO.LOW) + step_count=-step_count + for x in range(step_count): + if ES_enable == True and GPIO.input(ES_pin) != ES_start_state and motor != 'tt': + i = 0 + while i <= 10: + if GPIO.input(ES_pin) == ES_start_state: + i = 11 + if i == 10: + return + i = i + 1 + + GPIO.output(steppin, GPIO.HIGH) + if x<=ramp and x<=step_count/2: + delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) + #delay=delay_init+(ramp-x)*(delay_init)/acc + elif step_count-x<=ramp and x>step_count/2: + delay = delay_init * (1-1/acc*cos(1*(ramp+x-step_count)/ramp)+1/acc) + #delay=delay_init+(ramp-step_count+x)*(delay_init)/acc + else: + delay = delay_init + sleep(delay) + GPIO.output(steppin, GPIO.LOW) + sleep(delay) + +def ringlight(number,state): + import RPi.GPIO as GPIO + msg = {'cmd':'set'} + pin = load_int('pin_ringlight' + str(number)) + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + GPIO.setup(pin, GPIO.OUT) + GPIO.output(pin, state) + +def take_photo(file): + from os import system + filepath = basepath + file + + model=load_str('model') + + shutter = str(load_int('cam_shutter')) + saturation = load_str('cam_saturation') + contrast = load_str('cam_contrast') + awbg_red = load_str('cam_awbg_red') + awbg_blue = load_str('cam_awbg_blue') + gain = load_str('cam_gain') + quality = load_int('cam_jpeg_quality') + filepath2 = '/home/pi/OpenScan/tmp/tmp.jpg' + #width = load_str('cam_resx') + #height = load_str('cam_resy') + timeout = load_str('cam_timeout') + cropx = load_int('cam_cropx')/200 + cropy = load_int('cam_cropy')/200 + rotation = load_int('cam_rotation') + AF = load_bool('cam_AFmode') + camera = load_str('camera') + + + if camera == 'imx519' and AF == True: + autofocus = ' --autofocus ' + else: + autofocus = '' + + if camera == "usb_webcam": + cmd = 'fswebcam -i 0 -r "1280x720" -F 5 --no-banner --jpeg 95 --save ' + filepath2 + else: + cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + ' >/dev/null 2>&1' + # cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + + system(cmd) + return cmd + +def get_points(samples=1): + from math import pi, sqrt, acos, atan2, cos, sin + + points = [] + phi = pi * (3. - sqrt(5.)) + for i in range(int(samples)): + y = 1 - (i / float(samples - 1)) * 2 + radius = sqrt(1 - y * y) + theta = phi * i + x = cos(theta) * radius + z = sin(theta) * radius + r=sqrt(x*x+y*y+z*z) + theta_neu=acos(z/r)*180/pi + phi_neu=atan2(y,x)*180/pi + points.append((theta_neu-90,phi_neu)) + points.sort() + return points + +def create_coordinates(angle_min, angle_max,point_count): + point_count_final=point_count + if angle_max < angle_min: + a = angle_min + angle_min = angle_max + angle_max = a + point_count=point_count*90/(angle_max-angle_min) + actual_points=0 + while actual_pointsangle_min and x20: + point_count=point_count+3 + else: + point_count=point_count+1 + return filtered + + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/2024-1o/stable/OpenScanStatistics.py b/update/2024-1o/stable/OpenScanStatistics.py new file mode 100755 index 0000000..8adf9dd --- /dev/null +++ b/update/2024-1o/stable/OpenScanStatistics.py @@ -0,0 +1,38 @@ +import json +import os +from datetime import datetime +from dataclasses import dataclass + +@dataclass +class ScanData: + arch: str + openscan_version: str + openscan_branch: str + shield: str + date_init: str # Format: YYYY-MM-DD HH:MM + date_end: str # Format: YYYY-MM-DD HH:MM + num_photos: int + done_photos: int + camera: str + stack_size: int + telegram_enabled: bool + delete_aborted: bool + endstop_enabled: bool + group_stack_photos: bool + aborted: bool + +class ScanStatistics: + def __init__(self, filename: str = "/home/pi/OpenScan/statistics") -> None: + self.filename: str = filename + + def write_statistics(self, scan_data: ScanData) -> None: + data: dict = scan_data.__dict__ # Convert dataclass to dictionary + + # Parse date_init to get year and month + date_object: datetime = datetime.strptime(scan_data.date_init, "%Y-%m-%d %H:%M") + record_filename: str = os.path.join(self.filename, f"statistics-{date_object.year}-{date_object.month:02d}.json") + + # Append the new data as a new line + with open(record_filename, "a") as json_file: + json.dump(data, json_file, separators=(',', ':'), indent=None) # Collapsed JSON + json_file.write('\n') # Add a newline after each entry \ No newline at end of file diff --git a/update/main/config.txt b/update/2024-1o/stable/config.txt old mode 100644 new mode 100755 similarity index 94% rename from update/main/config.txt rename to update/2024-1o/stable/config.txt index ce06bd8..4faf2c8 --- a/update/main/config.txt +++ b/update/2024-1o/stable/config.txt @@ -2,10 +2,8 @@ # http://rpf.io/configtxt # Some settings may impact device functionality. See link above for details - # uncomment if you get no picture on HDMI for a default "safe" mode #hdmi_safe=1 -hdmi_blanking=2 # uncomment the following to adjust overscan. Use positive numbers if console # goes off screen, and negative if there is too much border @@ -55,13 +53,13 @@ hdmi_blanking=2 dtparam=audio=on # Automatically load overlays for detected cameras -camera_auto_detect=0 +camera_auto_detect=1 # Automatically load overlays for detected DSI displays display_auto_detect=1 # Enable DRM VC4 V3D driver -#dtoverlay=vc4-kms-v3d +dtoverlay=vc4-kms-v3d max_framebuffers=2 # Disable compensation for displays with overscan @@ -73,13 +71,14 @@ disable_overscan=1 # (e.g. for USB device mode) or if USB support is not required. otg_mode=1 +[all] + [pi4] # Run as fast as firmware / board allows arm_boost=1 [all] - camera_auto_detect=0 gpu_mem=256 -dtoverlay=vc4-fkms-v3d -dtoverlay=imx519,media-controller=1 +dtoverlay=imx519 +#dtoverlay=imx519,media-controller=1 diff --git a/update/2024-1o/stable/fla.py b/update/2024-1o/stable/fla.py new file mode 100644 index 0000000..026867e --- /dev/null +++ b/update/2024-1o/stable/fla.py @@ -0,0 +1,519 @@ +from flask import Flask, request, redirect, send_file, send_from_directory +from flask_restx import Resource, Api, Namespace +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont +from time import sleep, time +from OpenScan import load_int, load_float, load_bool, ringlight, motorrun +import RPi.GPIO as GPIO +from math import sqrt +import os +import math +from skimage import feature, color, transform +import numpy as np +from scipy import ndimage +import socket + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +app = Flask(__name__) +api = Api(app, version='1.0', title='OpenScan API', description='API for OpenScan') + +v1 = Namespace('v1', description='API v1') +# Create a namespace for system operations +system_ns = Namespace('system', description='System operations') +camera_ns = Namespace('camera', description='Camera operations') +motor_ns = Namespace('motor', description='Motor operations') + +api.add_namespace(v1, path='/v1') +api.add_namespace(system_ns, path='/v1/system') +api.add_namespace(camera_ns, path='/v1/camera') +api.add_namespace(motor_ns, path='/v1/motor') + +basedir = '/home/pi/OpenScan/' +timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + + +################################################################################################################### + + +@system_ns.route('/status') +class Status(Resource): + def get(self): + ''' + Get system status + ''' + import os + import json + from time import time + + if os.path.exists('/tmp/status.json'): + try: + with open('/tmp/status.json', 'r') as status_file: + status = json.load(status_file) + + elapsed_time = time() - status['start_time'] + estimated_total_time = (elapsed_time / status['current_photo']) * status['total_photos'] + time_remaining = max(0, estimated_total_time - elapsed_time) + + status.update({ + "status": "running", + "elapsed_time": int(elapsed_time), + "estimated_total_time": int(estimated_total_time), + "time_remaining": int(time_remaining) + }) + + return status, 200 + except Exception as e: + return {"error": f"Error reading status file: {str(e)}"}, 500 + else: + return {"status": "idle"}, 200 + +@system_ns.route('/shutdown') +class Shutdown(Resource): + @system_ns.doc(params={'token': 'Shutdown token for authentication'}) + def get(self): + '''Shutdown the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('shutdown -h now') + return {'message': 'Shutting down'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/reboot') +class Reboot(Resource): + @system_ns.doc(params={'token': 'Reboot token for authentication'}) + def get(self): + '''Reboot the Raspberry Pi''' + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + with open("/home/pi/OpenScan/settings/session_token", "r") as f: + session_token = f.readline()[:20] + + if shutdown_token == session_token or True: + delay = 0.1 + ringlight(2, False) + + for _ in range(5): + ringlight(1, True) + sleep(delay) + ringlight(1, False) + sleep(delay) + + os.system('reboot -h') + return {'message': 'Rebooting'}, 200 + else: + return redirect("http://" + hostname, code=302) + +@system_ns.route('/ringlight') +class Ringlight(Resource): + @system_ns.doc(params={'state': 'Ringlight state (0 or 1)'}) + def get(self): + '''Set ringlight state''' + state = int(request.args.get('state')) + if state == 0: + ringlight(1, False) + ringlight(2, False) + else: + ringlight(1, True) + ringlight(2, True) + return {'message': f'Ringlight set to {state}'}, 200 + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) + + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') + + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wait 3-5s + return {'message': 'Auto focus triggered'}, 200 + +@motor_ns.route('/motor_run') +class MotorRun(Resource): + ''' + Run a motor + ''' + @motor_ns.doc(params={ + 'motor': 'Motor name (rotor, tt, extra)', + 'angle': 'Angle to rotate (integer)', + 'ES_enable': 'Enable endstop (optional, boolean)', + 'ES_start_state': 'Endstop start state (optional, boolean)' + }) + @motor_ns.response(400, 'Bad Request') + def get(self): + '''Run a motor''' + motor = request.args.get('motor') + if not motor: + return {'error': 'Motor parameter is required'}, 400 + if motor not in ['rotor', 'tt', 'extra']: + return {'error': 'Invalid motor name'}, 400 + + try: + angle = int(request.args.get('angle')) + except (TypeError, ValueError): + return {'error': 'Angle must be an integer'}, 400 + + ES_enable = request.args.get('ES_enable', 'false').lower() == 'true' + ES_start_state = request.args.get('ES_start_state', 'true').lower() == 'true' + + try: + motorrun(motor, angle, ES_enable, ES_start_state) + except Exception as e: + return {'error': f'Error running motor: {str(e)}'}, 500 + + return {'message': f'Motor {motor} run to {angle} degrees'}, 200 + + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + + +if __name__ == '__main__': +# app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) + app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) + diff --git a/update/2024-1o/stable/flows.json b/update/2024-1o/stable/flows.json new file mode 100644 index 0000000..d46d3d0 --- /dev/null +++ b/update/2024-1o/stable/flows.json @@ -0,0 +1,9778 @@ +[ + { + "id": "e6f4d02efb300ea9", + "type": "tab", + "label": "Init", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "481edaf6db5a7a54", + "type": "tab", + "label": "Scan", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "80a3942785a26c29", + "type": "tab", + "label": "Files", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "e43a27722b508115", + "type": "tab", + "label": "Settings", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "a5557543ccff5889", + "type": "tab", + "label": "Update", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "87715429b0b1c9a3", + "type": "tab", + "label": "Statistics", + "disabled": false, + "info": "", + "env": [] + }, + { + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", + "type": "ui_tab", + "name": "Scan", + "icon": "dashboard", + "order": 2, + "disabled": false, + "hidden": false + }, + { + "id": "5c06cb6bcc371ee6", + "type": "ui_base", + "theme": { + "name": "theme-dark", + "lightTheme": { + "default": "#0094CE", + "baseColor": "#0094CE", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "darkTheme": { + "default": "#097479", + "baseColor": "#097479", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "edited": true, + "reset": false + }, + "customTheme": { + "name": "Untitled Theme 1", + "default": "#4B7930", + "baseColor": "#4B7930", + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false + }, + "themeState": { + "base-color": { + "default": "#097479", + "value": "#097479", + "edited": false + }, + "page-titlebar-backgroundColor": { + "value": "#097479", + "edited": false + }, + "page-backgroundColor": { + "value": "#111111", + "edited": false + }, + "page-sidebar-backgroundColor": { + "value": "#333333", + "edited": false + }, + "group-textColor": { + "value": "#0eb8c0", + "edited": false + }, + "group-borderColor": { + "value": "#555555", + "edited": false + }, + "group-backgroundColor": { + "value": "#333333", + "edited": false + }, + "widget-textColor": { + "value": "#eeeeee", + "edited": false + }, + "widget-backgroundColor": { + "value": "#097479", + "edited": false + }, + "widget-borderColor": { + "value": "#333333", + "edited": false + }, + "base-font": { + "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + } + }, + "angularTheme": { + "primary": "indigo", + "accents": "blue", + "warn": "red", + "background": "grey", + "palette": "light" + } + }, + "site": { + "name": "OpenScan", + "hideToolbar": "false", + "allowSwipe": "false", + "lockMenu": "false", + "allowTempTheme": "true", + "dateFormat": "DD/MM/YYYY", + "sizes": { + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, + "cx": 6, + "cy": 6, + "px": 0, + "py": 0 + } + } + }, + { + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 8 + }, + { + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 7 + }, + { + "id": "b5fdd57b.15eda8", + "type": "ui_group", + "name": "Main", + "tab": "15a222ed.d70a7d", + "order": 1, + "disp": false, + "width": 13, + "collapse": false + }, + { + "id": "db43d646.2074c8", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", + "order": 2, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "15a222ed.d70a7d", + "type": "ui_tab", + "name": "Files&Cloud", + "icon": "dashboard", + "order": 3, + "disabled": false, + "hidden": false + }, + { + "id": "365a30d0dfa83e95", + "type": "ui_group", + "name": "settings", + "tab": "e23b837a9f040895", + "order": 1, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "ac7409105cfecac6", + "type": "ui_group", + "name": "advanced", + "tab": "e23b837a9f040895", + "order": 3, + "disp": false, + "width": 7, + "collapse": false, + "className": "" + }, + { + "id": "729f9ea6e3513c9b", + "type": "ui_group", + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "b3150b13e34b1fe8", + "type": "ui_tab", + "name": "OpenScan", + "icon": "dashboard", + "order": 1, + "disabled": false, + "hidden": true + }, + { + "id": "ddbd496e.93a288", + "type": "ui_group", + "name": "Manage Updates", + "tab": "d25e08b4.5b27e8", + "order": 1, + "disp": true, + "width": "6", + "collapse": false + }, + { + "id": "3ce32450.e0cffc", + "type": "ui_group", + "name": "System & Stats", + "tab": "d25e08b4.5b27e8", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "d25e08b4.5b27e8", + "type": "ui_tab", + "name": "Update & Info", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "4390b2ebcbbe104c", + "type": "ui_group", + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "8ab79a98e536e0d6", + "type": "ui_group", + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Rotor", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 5, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 1, + "width": 1, + "height": 1 + }, + { + "id": "33b6d7317d1524b8", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "aaf5b874c52a58aa", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, + "height": 1 + }, + { + "id": "f8d8740dcbf499fb", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 11, + "width": 1, + "height": 1 + }, + { + "id": "7ac0cb556740d159", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, + "height": 1 + }, + { + "id": "4de2414e29020c74", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "90223f7ddc082321", + "order": 2, + "width": 7, + "height": 1 + }, + { + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 + }, + { + "id": "ce21673092264c38", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, + "height": 1 + }, + { + "id": "3f7b77f8a1675d27", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "12b719cba49817c9", + "order": 7, + "width": 4, + "height": 1 + }, + { + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 8, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "ac59b8fb186de073", + "type": "ui_group", + "name": "Statistics", + "tab": "656b4eb8b15dab8f", + "order": 3, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "656b4eb8b15dab8f", + "type": "ui_tab", + "name": "Statistics", + "icon": "dashboard", + "order": 6, + "disabled": false, + "hidden": false + }, + { + "id": "0b244f698c7ac9a2", + "type": "ui_group", + "name": "Shield Type", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "f622137daacdfebe", + "type": "ui_group", + "name": "Group 3", + "tab": "b3150b13e34b1fe8", + "order": 3, + "disp": true, + "width": 6 + }, + { + "id": "38d121ea5b2bd77d", + "type": "ui_group", + "name": "Turntable", + "tab": "457102eadc9ddb6c", + "order": 9, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, + { + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 520, + "wires": [ + [ + "949bafced17d66d6" + ] + ] + }, + { + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "a1f0ed7d5a9d670e", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "0.1", + "topic": "", + "x": 110, + "y": 60, + "wires": [ + [ + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6", + "d81572486f15cd7a" + ] + ] + }, + { + "id": "544d20f02215011a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'openscan_branch':'stable',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 330, + "y": 60, + "wires": [ + [ + "c77552216a8bb781" + ] + ] + }, + { + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 540, + "y": 60, + "wires": [ + [ + "960912e90ba5b5bc" + ] + ] + }, + { + "id": "960912e90ba5b5bc", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244", + "9b3e6a06c82a0f52", + "fbc5fc2e65311f8b" + ], + "x": 645, + "y": 60, + "wires": [] + }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "168d72a54504b327", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "5/0.1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "5", + "topic": "", + "payload": "", + "payloadType": "str", + "x": 100, + "y": 440, + "wires": [ + [ + "6c6ef2255a7d39e5" + ] + ] + }, + { + "id": "6c6ef2255a7d39e5", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "repeat 5s/0.1s", + "mode": "link", + "links": [ + "61990987acd0f263", + "2415272f42ce468c", + "6bf8344af427a6ba" + ], + "x": 205, + "y": 440, + "wires": [] + }, + { + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", + "outputs": 1, + "x": 270, + "y": 140, + "wires": [ + [ + "eb1a2387a1eeea76" + ] + ] + }, + { + "id": "b1e2491c952f84c9", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, + "wires": [ + [ + "200d4b9951b6e066" + ] + ] + }, + { + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "65518f3d4e3095e5", + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 800, + "y": 40, + "wires": [ + [ + "544d20f02215011a" + ] + ] + }, + { + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 650, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", + "outputs": 1, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 600, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 680, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 600, + "wires": [ + [] + ] + }, + { + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 640, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 720, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "8955d11554f55e63", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "", + "order": 1, + "width": 6, + "height": 3, + "passthru": false, + "label": "Install Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "date", + "topic": "", + "topicType": "str", + "x": 120, + "y": 820, + "wires": [ + [ + "1e7457ea9c2c5e09" + ] + ] + }, + { + "id": "1e7457ea9c2c5e09", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "update", + "mode": "link", + "links": [ + "39a502b38837273d" + ], + "x": 245, + "y": 820, + "wires": [] + }, + { + "id": "245e4341d4fb611c", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 790, + "y": 540, + "wires": [ + [ + "627406f3611511dc" + ] + ] + }, + { + "id": "627406f3611511dc", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "write", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "outputs": 1, + "x": 930, + "y": 540, + "wires": [ + [ + "50eeb3e362f9027f" + ] + ] + }, + { + "id": "88b1bddde110298a", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", + "topic": "", + "x": 650, + "y": 540, + "wires": [ + [ + "245e4341d4fb611c" + ] + ] + }, + { + "id": "50eeb3e362f9027f", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "1dffb799fdf10cbc", + "2afb6a45c73fa244", + "2e9b29c70969cf01", + "2f4c0f98.dee2", + "3876d5cbd248592b", + "592ec13d8f8923a9", + "5e7d5e4335d37794", + "9b3e6a06c82a0f52", + "9fd259de91de1da1", + "b4c843620c251c43", + "cb40b9341bd22a28", + "d0104e0163745993", + "d1efcd5fa9d25785", + "da61581182b7299e", + "e5f38b4a07a5e278", + "fbc5fc2e65311f8b", + "fd0258418489839d" + ], + "x": 1015, + "y": 540, + "wires": [] + }, + { + "id": "4f3121f158f06a61", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", + "outputs": 1, + "x": 860, + "y": 580, + "wires": [ + [] + ] + }, + { + "id": "4a8a04b1e5dca8fe", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "run rotor till endstop", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 690, + "y": 580, + "wires": [ + [ + "4f3121f158f06a61" + ] + ] + }, + { + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n
    \n
  • speed improvement 2-3x
  • \n
  • currently tested on OpenScan Mini + IMX519 with RPi 4
  • \n
  • optimized toolpath
  • \n
  • more responsive user interface
  • \n
  • hotspot mode (when no wireless network available ssid: openscan pw: opensource
  • \n
  • preview features and sharpness
  • \n
  • partial background masking
  • \n
  • no more autofocus --> instead you can set a min and max focus distance
  • \n
\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 580, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "e548168473aa85d6", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 5, + "width": 0, + "height": 0, + "passthru": false, + "label": "Statistics", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "5", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 100, + "y": 760, + "wires": [ + [ + "62cd5288.2805fc" + ] + ] + }, + { + "id": "d81572486f15cd7a", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "loadl", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'openscan_version'\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.payload = String(data);\nflow.set('openscan_version',data)\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 360, + "wires": [ + [ + "b1b0ccb783dd5882" + ] + ] + }, + { + "id": "b1b0ccb783dd5882", + "type": "change", + "z": "e6f4d02efb300ea9", + "name": "openscan_version", + "rules": [ + { + "t": "set", + "p": "openscan_version", + "pt": "flow", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 415, + "y": 360, + "wires": [ + [ + "0d8c6bc7887fb3c2" + ] + ] + }, + { + "id": "6a3d9acbe097a3d2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 120, + "wires": [ + [ + "cb6ebdabaaf7d0da" + ] + ] + }, + { + "id": "7ef6f1b5c67201fe", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 120, + "wires": [ + [] + ] + }, + { + "id": "86f7d1b2d763f6e2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 160, + "wires": [ + [ + "c8a3fde5206ce1ae" + ] + ] + }, + { + "id": "fd799c931139764d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 240, + "wires": [ + [ + "87be854db758a9a6" + ] + ] + }, + { + "id": "d5140d455122c49a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 280, + "wires": [ + [ + "9daea4bd57f7a00e" + ] + ] + }, + { + "id": "194f3590dd4f6e3d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 240, + "wires": [ + [] + ] + }, + { + "id": "2de69452e829d780", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 280, + "wires": [ + [] + ] + }, + { + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", + "label": "", + "tooltip": "", + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, + "height": 1, + "passthru": true, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 320, + "y": 80, + "wires": [ + [ + "734ac3bff2df6837" + ] + ] + }, + { + "id": "97170908e1f4ac55", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 80, + "wires": [ + [ + "58e565fea35cb667" + ] + ] + }, + { + "id": "734ac3bff2df6837", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 80, + "wires": [ + [] + ] + }, + { + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 55, + "y": 80, + "wires": [ + [ + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" + ] + ] + }, + { + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/v1/camera/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", + "outputs": 1, + "x": 510, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "c7f5808d753480d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 170, + "y": 200, + "wires": [ + [ + "11f41a6030578ef4" + ] + ] + }, + { + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 200, + "wires": [ + [ + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "855cbcadef1163c5", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 840, + "wires": [ + [ + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" + ] + ] + }, + { + "id": "1a443e20a973d2f1", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw true", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 630, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "d1b87196ae5373ed", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw false", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 430, + "y": 760, + "wires": [ + [] + ] + }, + { + "id": "03d92601c62b79d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "4s/0.5", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "Repeat", + "payload": "0.1", + "payloadType": "str", + "x": 100, + "y": 840, + "wires": [ + [ + "855cbcadef1163c5" + ] + ] + }, + { + "id": "41e6a4649b6afbfb", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Take Preview Shot", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/v1/camera/picam2_take_photo')\n\nreturn msg\n", + "outputs": 1, + "x": 450, + "y": 800, + "wires": [ + [ + "1a443e20a973d2f1", + "296636b7467fc745" + ] + ] + }, + { + "id": "85a268108250ba88", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", + "order": 1, + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 450, + "y": 840, + "wires": [ + [ + "417f653ca0dfdcfc", + "180476141c2a44ad" + ] + ] + }, + { + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, + "wires": [] + }, + { + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, + "wires": [ + [ + "e864254b18c23dd1" + ] + ] + }, + { + "id": "e864254b18c23dd1", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int\n\nif 'payload' not in msg:\n return\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'))\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'))\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'))\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'))\n\n", + "outputs": 1, + "x": 780, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "180476141c2a44ad", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 880, + "wires": [ + [ + "8cbdbfecbd12ef83" + ] + ] + }, + { + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", + "outputs": 1, + "x": 870, + "y": 880, + "wires": [ + [] + ] + }, + { + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", + "outputs": 1, + "x": 440, + "y": 720, + "wires": [ + [ + "923be3b2b25224b4" + ] + ] + }, + { + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "c8a3fde5206ce1ae", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 160, + "wires": [ + [ + "034ec9f59e50a361", + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "034ec9f59e50a361", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, + "wires": [ + [ + "194f3590dd4f6e3d" + ] + ] + }, + { + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, + "wires": [ + [ + "2de69452e829d780" + ] + ] + }, + { + "id": "cb6ebdabaaf7d0da", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 120, + "wires": [ + [ + "7ef6f1b5c67201fe" + ] + ] + }, + { + "id": "82ecd3cd971cb7ea", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, + "height": 1, + "name": "projectname", + "label": "Projectname", + "format": "", + "layout": "row-left", + "className": "", + "x": 530, + "y": 40, + "wires": [] + }, + { + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, + "wires": [ + [ + "06e1e19835a9816e" + ] + ] + }, + { + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, + "wires": [ + [ + "1fe18f3b0b52aabd" + ] + ] + }, + { + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "7dd287f40385922f", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "start ", + "group": "365a30d0dfa83e95", + "order": 10, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-play", + "payload": "", + "payloadType": "date", + "topic": "enabled", + "topicType": "str", + "x": 130, + "y": 1040, + "wires": [ + [ + "33d94a04b96a2de0", + "6d15f717d5a11002", + "9a6b30a0175a8ecd" + ] + ] + }, + { + "id": "579f2211199fd6ab", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "stop", + "group": "365a30d0dfa83e95", + "order": 12, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-stop", + "payload": "numberofphotos", + "payloadType": "global", + "topic": "", + "topicType": "str", + "x": 490, + "y": 1100, + "wires": [ + [ + "1787f08ed7070ddd", + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "1787f08ed7070ddd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "stop", + "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "outputs": 1, + "x": 630, + "y": 1100, + "wires": [ + [] + ] + }, + { + "id": "e9b13dfd9f8d3711", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 395, + "y": 1000, + "wires": [] + }, + { + "id": "9654deebb668e012", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "1s", + "props": [ + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 290, + "y": 1140, + "wires": [ + [ + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "8367cfa0bf5bc5df", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine", + "links": [ + "200d4b9951b6e066", + "8689e938.dd9e38", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 45, + "y": 1040, + "wires": [ + [ + "7dd287f40385922f" + ] + ] + }, + { + "id": "fb13752beddee9f2", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 535, + "y": 1060, + "wires": [] + }, + { + "id": "33d94a04b96a2de0", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1100, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "c1c044f3c2139f68", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 1140, + "wires": [ + [ + "579f2211199fd6ab" + ] + ] + }, + { + "id": "1daf9e3a5bd5ab48", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 430, + "y": 1040, + "wires": [ + [ + "fb13752beddee9f2" + ] + ] + }, + { + "id": "6d15f717d5a11002", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 1000, + "wires": [ + [ + "e9b13dfd9f8d3711" + ] + ] + }, + { + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "# The contents of this file are embedded in the OpenScan app (Node-RED)\nfrom OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom OpenScanStatistics import ScanStatistics, ScanData\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\nfrom datetime import datetime\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname, remove\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\nimport json\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\nstats = ScanStatistics()\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/v1/camera/picam2_switch_mode?mode=1')\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\narchitecture = load_str(\"architecture\")\nopenscan_version = load_str(\"openscan_version\")\nopenscan_branch = load_str(\"openscan_branch\")\ncamera_model = load_str(\"camera\")\nshield = load_str(\"shield_type\")\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\ndelete_aborted = load_bool('delete_aborted')\nrotate_tt_first = load_bool('rotate_tt_first')\nendstop_enable = load_bool('rotor_enable_endstop')\nif endstop_enable:\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True, False)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_current_timestamp():\n return datetime.now().strftime(\"%Y-%m-%d %H:%M\")\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/v1/camera/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/v1/camera/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/v1/camera/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n \n if rotate_tt_first:\n motorrun('tt',tt_angle)\n motorrun('rotor',rotor_angle)\n else:\n motorrun('rotor',rotor_angle)\n motorrun('tt',tt_angle)\n return\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/v1/camera/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\ncounter2 = 0\n\ndate_init = get_current_timestamp()\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\n\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n \n # Calculate time remaining and write status to /tmp/status as JSON\n elapsed_time = time() - starttime\n estimated_total_time = (elapsed_time / counter) * photocount * steps\n time_remaining = max(0, estimated_total_time - elapsed_time)\n \n status = {\n \"scan_name\": projectname,\n \"total_photos\": photocount,\n \"current_photo\": counter,\n \"stacksize\": steps,\n \"start_time\": int(starttime),\n }\n with open('/tmp/status.json', 'w') as status_file:\n json.dump(status, status_file)\n\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/v1/camera/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\ntry:\n remove('/tmp/status.json')\nexcept FileNotFoundError:\n pass # File doesn't exist, so no need to delete\nexcept Exception as e:\n print(f\"Error deleting /tmp/status.json: {e}\")\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\ndate_end = get_current_timestamp()\n\n\nif counter == photocount:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n aborted=False\nelse:\n aborted=True\n if delete_aborted:\n remove(zippath)\n else:\n system('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nscan_data = ScanData(\n arch=architecture,\n openscan_version=openscan_version,\n openscan_branch=openscan_branch,\n shield=shield,\n date_init=date_init,\n date_end=date_end,\n num_photos=photocount,\n done_photos=counter,\n camera=camera_model,\n stack_size=stacksize,\n telegram_enabled=telegram_enable,\n delete_aborted=delete_aborted,\n endstop_enabled=endstop_enable,\n group_stack_photos=group_stack_photos,\n aborted=aborted\n)\n\nstats.write_statistics(scan_data)\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, + "wires": [ + [ + "1daf9e3a5bd5ab48", + "795c85ad4f109567" + ] + ] + }, + { + "id": "afe47a9eaae6f67f", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, + "height": 1, + "name": "", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", + "className": "", + "x": 340, + "y": 40, + "wires": [] + }, + { + "id": "8608517d0567d63f", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 40, + "wires": [ + [ + "afe47a9eaae6f67f" + ] + ] + }, + { + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 55, + "y": 40, + "wires": [ + [ + "8608517d0567d63f" + ] + ] + }, + { + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, + "wires": [ + [ + "9774e7ad3b506354" + ] + ] + }, + { + "id": "9774e7ad3b506354", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 380, + "wires": [ + [ + "f0af909f3e739b22" + ] + ] + }, + { + "id": "39c744466a21735e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 40, + "wires": [ + [ + "fa181d22775c2ce6" + ] + ] + }, + { + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 80, + "wires": [ + [ + "c615034ea6b26174" + ] + ] + }, + { + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 480, + "wires": [ + [ + "237c2135cdad86ea" + ] + ] + }, + { + "id": "dd7fb8791d34c751", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 880, + "wires": [ + [ + "180476141c2a44ad" + ] + ] + }, + { + "id": "5baf89a2682265f7", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "enable led", + "links": [ + "eb1a2387a1eeea76" + ], + "x": 145, + "y": 880, + "wires": [ + [ + "dd7fb8791d34c751" + ] + ] + }, + { + "id": "6a26e8a7253d708c", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 40, + "wires": [ + [ + "39c744466a21735e" + ] + ] + }, + { + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, + "wires": [ + [ + "61aab497fa50898e" + ] + ] + }, + { + "id": "9fd259de91de1da1", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 735, + "y": 40, + "wires": [ + [ + "6a26e8a7253d708c", + "35ad7e55833836c1" + ] + ] + }, + { + "id": "fa181d22775c2ce6", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 40, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "c615034ea6b26174", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 80, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "ae5ee8787145906d", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import camera\ncamera('/v1/camera/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", + "outputs": 1, + "x": 1290, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "f0af909f3e739b22", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Features", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 420, + "wires": [ + [ + "710fc2dbb5ef0167" + ] + ] + }, + { + "id": "710fc2dbb5ef0167", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "d93c2b67bcf23b9a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 480, + "wires": [ + [ + "5e83b653850fa16e" + ] + ] + }, + { + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 95, + "y": 480, + "wires": [ + [ + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" + ] + ] + }, + { + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "c8b93b42c720b9cf", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", + "links": [ + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" + ], + "x": 85, + "y": 380, + "wires": [ + [ + "78cfe60013a1bea4" + ] + ] + }, + { + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 560, + "y": 960, + "wires": [] + }, + { + "id": "ea54fcc2.cfcc2", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "get dirs", + "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "outputs": 1, + "x": 480, + "y": 180, + "wires": [ + [ + "f3662f8c7d3d7a2d", + "01e4783e148c6698" + ] + ] + }, + { + "id": "2f4c0f98.dee2", + "type": "link in", + "z": "80a3942785a26c29", + "name": "filelist", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "a4f09e25.02569", + "ed35109311335099", + "fb13752beddee9f2" + ], + "x": 355, + "y": 220, + "wires": [ + [ + "ea54fcc2.cfcc2" + ] + ] + }, + { + "id": "952ce286.4ffd4", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 4, + "width": 6, + "height": 1, + "name": "Status", + "label": "Status", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 250, + "y": 60, + "wires": [] + }, + { + "id": "d4383424.7807c8", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "upload", + "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", + "outputs": 2, + "x": 530, + "y": 460, + "wires": [ + [ + "9a132ab1.b21658" + ], + [ + "3d16b3789632784d", + "9a132ab1.b21658" + ] + ] + }, + { + "id": "50710948.71c308", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "set", + "pt": "global", + "to": "payload", + "tot": "msg" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 750, + "y": 180, + "wires": [ + [ + "ada1b6f7cccc9344", + "85839a17fb7b58b9" + ] + ] + }, + { + "id": "834046a4.647938", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 5, + "width": 6, + "height": 1, + "name": "Set", + "label": "Set:", + "format": "{{msg.payload.Name}}", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 220, + "wires": [] + }, + { + "id": "9a132ab1.b21658", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.true", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 780, + "y": 460, + "wires": [ + [ + "8689e938.dd9e38" + ] + ] + }, + { + "id": "3c67e97b.9d19a6", + "type": "function", + "z": "80a3942785a26c29", + "name": "enable", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 130, + "y": 340, + "wires": [ + [ + "7a93d1e18254685c", + "e434ef42bd6b92e8", + "d5d840183025d91b", + "ab9e90ab5a53a0dd", + "478994f671a3907d" + ] + ] + }, + { + "id": "bfc01f26.c32cf", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.false", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 500, + "wires": [ + [ + "f20f2dbc.0f123" + ] + ] + }, + { + "id": "b33d604c.5f1a6", + "type": "link in", + "z": "80a3942785a26c29", + "name": "enable cloud", + "links": [ + "4082b136.dae18", + "8689e938.dd9e38", + "bd75f33b8a57c522", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 35, + "y": 340, + "wires": [ + [ + "3c67e97b.9d19a6" + ] + ] + }, + { + "id": "f6bd1a04.470838", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "set", + "tot": "global" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 410, + "y": 460, + "wires": [ + [ + "d4383424.7807c8" + ] + ] + }, + { + "id": "4082b136.dae18", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "b33d604c.5f1a6", + "87574a42938afec4" + ], + "x": 715, + "y": 140, + "wires": [] + }, + { + "id": "f20f2dbc.0f123", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 515, + "y": 500, + "wires": [] + }, + { + "id": "8689e938.dd9e38", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 875, + "y": 460, + "wires": [] + }, + { + "id": "15de0ebb.616d61", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 380, + "wires": [ + [ + "a7d89487.ee8858" + ] + ] + }, + { + "id": "a7d89487.ee8858", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", + "outputs": 1, + "x": 690, + "y": 380, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "a4f09e25.02569", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "2f4c0f98.dee2" + ], + "x": 775, + "y": 360, + "wires": [] + }, + { + "id": "7a93d1e18254685c", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "92c98e6ce7cd25f9" + ], + "x": 235, + "y": 500, + "wires": [] + }, + { + "id": "4d99c601c9881680", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "refresh", + "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", + "outputs": 2, + "x": 320, + "y": 180, + "wires": [ + [ + "ea54fcc2.cfcc2", + "b42e061fb1f1f3d7" + ], + [ + "6434e713f088012b" + ] + ] + }, + { + "id": "372e95797a3f2f3b", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "limit :)", + "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", + "outputs": 1, + "x": 90, + "y": 220, + "wires": [ + [ + "573edbfdb7500ddc" + ] + ] + }, + { + "id": "573edbfdb7500ddc", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 230, + "y": 220, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "dacb1f078b624e10", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 340, + "wires": [ + [ + "c8d65cc7c2ff7c36" + ] + ] + }, + { + "id": "92c98e6ce7cd25f9", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "7a93d1e18254685c", + "bd75f33b8a57c522" + ], + "x": 35, + "y": 180, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] + }, + { + "id": "3d16b3789632784d", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 770, + "y": 500, + "wires": [ + [] + ] + }, + { + "id": "6434e713f088012b", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 470, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "c8d65cc7c2ff7c36", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", + "outputs": 1, + "x": 690, + "y": 340, + "wires": [ + [ + "a4f09e25.02569" + ] + ] + }, + { + "id": "f4e9a4bd79b4221f", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 340, + "wires": [ + [ + "dacb1f078b624e10" + ] + ] + }, + { + "id": "2806bf08ea21216d", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 380, + "wires": [ + [ + "15de0ebb.616d61" + ] + ] + }, + { + "id": "61990987acd0f263", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 45, + "y": 60, + "wires": [ + [ + "51579603bce21e98" + ] + ] + }, + { + "id": "e8e488a6dd5d0b33", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "Download", + "order": 8, + "width": 3, + "height": 1, + "format": "\n
Download\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 880, + "y": 260, + "wires": [ + [] + ] + }, + { + "id": "0c387c0291d6c131", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 750, + "y": 260, + "wires": [ + [ + "e8e488a6dd5d0b33" + ] + ] + }, + { + "id": "e5f38b4a07a5e278", + "type": "link in", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 655, + "y": 220, + "wires": [ + [ + "834046a4.647938" + ] + ] + }, + { + "id": "e434ef42bd6b92e8", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "upload2", + "order": 7, + "width": 3, + "height": 1, + "format": "upload", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 460, + "wires": [ + [ + "f6bd1a04.470838" + ] + ] + }, + { + "id": "c46e10b9c201913e", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "refresh", + "order": 2, + "width": 4, + "height": 1, + "format": "refresh{{msg.text}}", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 160, + "y": 180, + "wires": [ + [ + "372e95797a3f2f3b", + "4d99c601c9881680" + ] + ] + }, + { + "id": "d5d840183025d91b", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del set", + "order": 11, + "width": 2, + "height": 1, + "format": "delete set", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 380, + "wires": [ + [ + "2806bf08ea21216d" + ] + ] + }, + { + "id": "ab9e90ab5a53a0dd", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del ", + "order": 10, + "width": 2, + "height": 1, + "format": "delete all", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 340, + "wires": [ + [ + "f4e9a4bd79b4221f" + ] + ] + }, + { + "id": "478994f671a3907d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "combine", + "order": 9, + "width": 2, + "height": 1, + "format": "combine", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 540, + "wires": [ + [ + "51bfd0fb7b1d292e" + ] + ] + }, + { + "id": "189c1eed09624a7b", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 580, + "wires": [ + [ + "1493398979a63775" + ] + ] + }, + { + "id": "51bfd0fb7b1d292e", + "type": "function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 420, + "y": 540, + "wires": [ + [] + ] + }, + { + "id": "da325be8e74179be", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", + "outputs": 1, + "x": 560, + "y": 580, + "wires": [ + [ + "ed35109311335099" + ] + ] + }, + { + "id": "ed35109311335099", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "2f4c0f98.dee2" + ], + "x": 655, + "y": 580, + "wires": [] + }, + { + "id": "1493398979a63775", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Combine", + "x": 420, + "y": 580, + "wires": [ + [ + "da325be8e74179be" + ] + ] + }, + { + "id": "ada1b6f7cccc9344", + "type": "link out", + "z": "80a3942785a26c29", + "name": "combine", + "mode": "link", + "links": [ + "6dd356510c446cf4" + ], + "x": 835, + "y": 180, + "wires": [] + }, + { + "id": "6dd356510c446cf4", + "type": "link in", + "z": "80a3942785a26c29", + "name": "combine", + "links": [ + "ada1b6f7cccc9344" + ], + "x": 175, + "y": 580, + "wires": [ + [ + "189c1eed09624a7b" + ] + ] + }, + { + "id": "b42e061fb1f1f3d7", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "397ab7f44b893c89", + "3876d5cbd248592b" + ], + "x": 435, + "y": 140, + "wires": [] + }, + { + "id": "b99505440832439f", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "diskspace", + "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", + "outputs": 1, + "x": 800, + "y": 100, + "wires": [ + [ + "92047434f8e9f927" + ] + ] + }, + { + "id": "92047434f8e9f927", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 950, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "f3662f8c7d3d7a2d", + "type": "delay", + "z": "80a3942785a26c29", + "name": "", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "minute", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 650, + "y": 100, + "wires": [ + [ + "b99505440832439f" + ] + ] + }, + { + "id": "51579603bce21e98", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "read", + "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", + "outputs": 1, + "x": 130, + "y": 60, + "wires": [ + [ + "952ce286.4ffd4" + ] + ] + }, + { + "id": "9a5baae623355f9d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "preview", + "order": 6, + "width": 6, + "height": 6, + "format": "
\n\n\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1020, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "85839a17fb7b58b9", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "preview", + "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", + "outputs": 1, + "x": 880, + "y": 220, + "wires": [ + [ + "9a5baae623355f9d" + ] + ] + }, + { + "id": "01e4783e148c6698", + "type": "ui_table", + "z": "80a3942785a26c29", + "group": "b5fdd57b.15eda8", + "name": "", + "order": 1, + "width": 13, + "height": 7, + "columns": [ + { + "field": "Date", + "title": "Date", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Name", + "title": "Name", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Photos", + "title": "Photos", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Duration", + "title": "ΔT", + "width": "60", + "align": "left", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Size", + "title": "Size", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Status", + "title": "Status", + "width": "140", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + } + ], + "outputs": 1, + "cts": true, + "x": 610, + "y": 180, + "wires": [ + [ + "4082b136.dae18", + "50710948.71c308", + "834046a4.647938", + "0c387c0291d6c131" + ] + ] + }, + { + "id": "cb3437ec113e1b6f", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "SSH", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 3, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 390, + "y": 360, + "wires": [ + [ + "c24f61b87e3226dd" + ] + ] + }, + { + "id": "60fd0adce1cfeb82", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Samba", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "test2", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 400, + "wires": [ + [ + "441d3ef525e901da" + ] + ] + }, + { + "id": "c24f61b87e3226dd", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "ssh", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", + "outputs": 1, + "x": 530, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "c013e836e759a085", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "4390b2ebcbbe104c", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "label": "Terms Of Use", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 120, + "y": 320, + "wires": [ + [ + "b78346ca3ce70c68" + ] + ] + }, + { + "id": "f0d8dbcca76a1926", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "Agree", + "cancel": "Disagree", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 410, + "y": 320, + "wires": [ + [ + "e95b86cbac1b03b9" + ] + ] + }, + { + "id": "34374044c0030625", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "General", + "group": "4390b2ebcbbe104c", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

General Settings

Terms Of Use

In order to use the OpenScanCloud, please read the terms of use as files will be transmitted from your device to the OpenScan Servers.

SSH

SSH can be used to access the Raspberry Pi and modify core files of the operating system. Please deactivate, if you do not want to use this feature.

If you want to use it, the default user is pi, password: raspberry. Please change the password immediately. 

Samba

Samba s a network local file sharing server, which allows accessing the Raspberry Pi's file system through the explorer (and other programs like FileZilla). You can use it to transfer custom photo sets to the device in order to use the OpenScanCloud. Therefore, you need to transfer the zip file containing your photos to the following folder /OpenScan/scans/

You can access the Raspberry Pis file system by inserting the following line into your Windows explorer: 

\\\\OpenScan/PiShare/OpenScan/scans/

username: pi, password: raspberry

Please deactivate the local file sharing if you do not intend to use it

Advanced Settings

Enable a ton of additional settings, which should be changed only if you know what you are doing ;)

Model

Device model you are using: OpenScan Mini or OpenScan Classic. Setting the device affects the settings of the motor (gear ratio, acceleration, speed). You can change those values manually in the advanced settings.

Camera

A wide range of camera modules is supported (Pi camera v1.3, v2.1, HQ, Arducam IMX519, IMX290, IMX378, OV9281). If you encounter any issues with those models, please check the orientation of the camera ribbon cable and its connectors.

DSLR (gphoto) - connect a wide range of DSLR cameras to the device through USB. See GPhoto for a full list of supported devices.

External camera - triggering any camera through an isolated GPIO signal on the front side of the pi shield.

Shutdown/Reboot

Always use the shutdown button before you power off your Raspberry Pi.

Restore Default Settings

In case you want to restore the default settings

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "b2b6bf23c9989133", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Pinout", + "group": "70d0be671bf03ca7", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Pinout

ONLY CHANGE THE PINOUT IF YOU ARE ABSOLUTELY SURE! CHANGES CAN DAMAGE THE RASPBERRY PI AND ANY PERIPHERALS!


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 220, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "441d3ef525e901da", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "smb", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", + "outputs": 1, + "x": 530, + "y": 400, + "wires": [ + [] + ] + }, + { + "id": "3256bab150113a48", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Motor", + "group": "7a3279eea439bcdd", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Motor Settings

Turntable Mode

Activate turntable mode in order to deactivate the rotor. The routine will only move the turntable and take a given number of photos.

Rotor - Start Angle, Min and Max Angle

Since this version of OpenScan does not have an endstop (yet), it is necessary to tell the device its position when the routine is being started. 0° corresponds to the horizontal (natural) orientation.

After that, the device will equally space the image positions between angle min and angle max.

Rotor/Turntable

Steps per rotation -  defines the number of steps it takes to move the axis 360°. It is defined by A*B*C, where A is the number of steps for one revolution of the given stepper motor (normally 200), B is the microstepping used (normally 16), and C the gear ratio (1 for the turntable and 15 or 5,33 for the OpenScan Mini and Classic respectively)

Delay - time in microseconds between each step of the motor. Lower this value if the movement is too fast

Acceleration - a factor defining how fast the delay time between each step is being changed during acceleration and deceleration phases. Lower this value in order to make the movement smoother.

Acceleration ramp - the number of steps allowed for the acceleration processes. Increase this value, if you want smoother movement.

Manual Angle - Defines the degree value for the manual movement through the arrow buttons in the scan menu

Direction - If needed, reverse the movement (in case the arrow buttons and movement do not correspond). Alternatively, you can flip the motor cable 180° (BUT MAKE SURE TO POWER OFF THE DEVICE!)


", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 430, + "y": 140, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "7a186669a17daa71", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "camera", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Camera Settings

Jpeg quality

Value in percent, which usually does not need to be changed.

Downscale Preview

The preview image has to be scaled down depending on your network speed. If you want to have a higher quality preview image, you can increase this value, which defines the maximal width/height value. If the value is too high, the preview window might not update

Image Rotation

Change the image rotation, if needed.

Timeout

Defines the time in seconds, when the libcamera command (used for the camera modules) will timeout. Increase this value, if the camera does not get triggered in each position.

Delay Before/After

A fixed delay in seconds before and/or after a photo is taken. Increase this value when the photos have visual motion blur.

AWBG, Gain, Contrast, Saturation

Under most circumstances, you do not need to touch these values.

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 420, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "edac7dd292e7e486", + "type": "comment", + "z": "e43a27722b508115", + "name": "General Settings", + "info": "", + "x": 120, + "y": 280, + "wires": [] + }, + { + "id": "161b52034e578ee2", + "type": "comment", + "z": "e43a27722b508115", + "name": "Network", + "info": "", + "x": 100, + "y": 720, + "wires": [] + }, + { + "id": "f6d6cc35679ede63", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "more sets", + "label": "Advanced Settings", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 5, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 480, + "wires": [ + [ + "f06a7bcad524e9f9" + ] + ] + }, + { + "id": "29745a36fc157f3f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "more sets", + "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", + "outputs": 2, + "x": 820, + "y": 480, + "wires": [ + [ + "8750ad979e9ea246" + ], + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "bf23328f9fb11b22", + "type": "ui_ui_control", + "z": "e43a27722b508115", + "name": "change visibility", + "events": "all", + "x": 600, + "y": 60, + "wires": [ + [] + ] + }, + { + "id": "b37be1d222bc70c9", + "type": "inject", + "z": "e43a27722b508115", + "name": "1s_repeater", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "1", + "crontab": "", + "once": true, + "onceDelay": "2", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 150, + "y": 60, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "89eedf29b404f750", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, + "wires": [ + [ + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" + ] + ] + }, + { + "id": "2050de5d9e02f69f", + "type": "comment", + "z": "e43a27722b508115", + "name": "Info Texts", + "info": "", + "x": 100, + "y": 140, + "wires": [] + }, + { + "id": "ded3086945a6d4b5", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "check ip address", + "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", + "outputs": 1, + "x": 250, + "y": 940, + "wires": [ + [ + "3cfe464506f46ecd" + ] + ] + }, + { + "id": "3cfe464506f46ecd", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Your local IP:", + "format": "{{msg.ip}}", + "layout": "row-spread", + "className": "", + "x": 430, + "y": 940, + "wires": [] + }, + { + "id": "bd206ad109831e6a", + "type": "comment", + "z": "e43a27722b508115", + "name": "OpenScanCloud", + "info": "", + "x": 120, + "y": 1260, + "wires": [] + }, + { + "id": "b70a9a665c1e4d36", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Cloud-settings", + "group": "12b719cba49817c9", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

OpenScanCloud

OpenScanCloud is a free/donation-based cloud processing service, which will convert your photos into 3d models using latest photogrammetry technology. Feel free to support the project with a small donation at BuyMeACoffee.

The only requirement to use this service is a one-time, free-of-charge registration (which is solely an anti-spam measure). By filling out the registration form, you will receive an individual access token.

Register

In order to use the OpenScanCloud, you will have to enter your name and email. It might take 1-3 days to create the access token, which will be sent to your mail address. Please check your spam folder.

Enter Token

Please enter your individual token here in order to activate the cloud functionality. The token will be verified immediately. In case of any problems, please contact cloud@openscan.eu

Token

A shorted version of your token will be displayed here. Please include a copy of this shorted token in any support requests cloud@openscan.eu

Credit (GB)

Each token comes with a given amount of 'credit' which is another measure against spam. The given number in Gigabyte indicates the amount of data, that you can process on the servers. 

IMPORTANT: The credit can be increased at any time by sending a (nice) mail to cloud@openscan.eu

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 740, + "y": 260, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "c9f0566601a3e130", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Number of Photos:", + "format": "{{msg.limit_photos}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 1400, + "wires": [] + }, + { + "id": "9bd86d27ea499a2a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "Max. Filesize (GB):", + "format": "{{msg.limit_filesize}}", + "layout": "row-spread", + "className": "", + "x": 390, + "y": 1440, + "wires": [] + }, + { + "id": "2c37f7030810d234", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Credit (GB):", + "format": "{{msg.credit}}", + "layout": "row-spread", + "className": "", + "x": 370, + "y": 1480, + "wires": [] + }, + { + "id": "f40286c18afd4501", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "save", + "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", + "outputs": 2, + "x": 750, + "y": 1340, + "wires": [ + [ + "455a5266017ea121", + "50f73cee213ec05c" + ], + [ + "264eece408043021" + ] + ] + }, + { + "id": "455a5266017ea121", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "topic": "", + "name": "", + "x": 890, + "y": 1300, + "wires": [ + [] + ] + }, + { + "id": "c368df68593bc2bf", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Token", + "tooltip": "", + "group": "12b719cba49817c9", + "order": 2, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 350, + "y": 1360, + "wires": [ + [ + "18fd1afa768187b3" + ] + ] + }, + { + "id": "18fd1afa768187b3", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "Save?", + "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", + "outputs": 2, + "x": 470, + "y": 1360, + "wires": [ + [ + "418aea2ec65573a0" + ], + [ + "9792c89c5f4429f9" + ] + ] + }, + { + "id": "f90a98899b7a71d0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "text", + "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", + "outputs": 1, + "x": 230, + "y": 1360, + "wires": [ + [ + "c368df68593bc2bf" + ] + ] + }, + { + "id": "b4c843620c251c43", + "type": "link in", + "z": "e43a27722b508115", + "name": "token", + "links": [ + "960912e90ba5b5bc", + "50f73cee213ec05c", + "9792c89c5f4429f9", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1360, + "wires": [ + [ + "f90a98899b7a71d0" + ] + ] + }, + { + "id": "418aea2ec65573a0", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 1340, + "wires": [ + [ + "f40286c18afd4501" + ] + ] + }, + { + "id": "9792c89c5f4429f9", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "b4c843620c251c43" + ], + "x": 555, + "y": 1380, + "wires": [] + }, + { + "id": "264eece408043021", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "5d267acc10020091", + "3876d5cbd248592b" + ], + "x": 835, + "y": 1380, + "wires": [] + }, + { + "id": "3876d5cbd248592b", + "type": "link in", + "z": "e43a27722b508115", + "name": "OSCparameters", + "links": [ + "960912e90ba5b5bc", + "264eece408043021", + "b42e061fb1f1f3d7", + "50eeb3e362f9027f" + ], + "x": 75, + "y": 1400, + "wires": [ + [ + "5daca3ec47f8e7fc" + ] + ] + }, + { + "id": "50f73cee213ec05c", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "links": [ + "b4c843620c251c43", + "5d267acc10020091" + ], + "x": 835, + "y": 1340, + "wires": [] + }, + { + "id": "95578e54a9b61cba", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 250, + "y": 1540, + "wires": [ + [ + "d7a5693da7855da8" + ] + ] + }, + { + "id": "d7a5693da7855da8", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", + "outputs": 2, + "x": 390, + "y": 1540, + "wires": [ + [ + "2b02b97dd1614e52" + ], + [ + "183a629accb417b1" + ] + ] + }, + { + "id": "183a629accb417b1", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1580, + "wires": [ + [] + ] + }, + { + "id": "2b02b97dd1614e52", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 530, + "y": 1540, + "wires": [ + [ + "3e4c15d7b538f816" + ] + ] + }, + { + "id": "3bf622f344172721", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "SUBMIT", + "cancel": "Cancel", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 810, + "y": 1540, + "wires": [ + [ + "e431cb2b8d217cee" + ] + ] + }, + { + "id": "e431cb2b8d217cee", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", + "outputs": 1, + "x": 950, + "y": 1540, + "wires": [ + [ + "106874534890f229" + ] + ] + }, + { + "id": "a38d7fde5c73210f", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Register", + "group": "12b719cba49817c9", + "order": 6, + "width": 2, + "height": 1, + "passthru": false, + "label": "Register", + "tooltip": "testtesttest", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "Please enter your email address:", + "payloadType": "str", + "topic": "Requesting an OpenScanCloud Token", + "topicType": "str", + "x": 100, + "y": 1540, + "wires": [ + [ + "95578e54a9b61cba" + ] + ] + }, + { + "id": "106874534890f229", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 1090, + "y": 1540, + "wires": [ + [] + ] + }, + { + "id": "5daca3ec47f8e7fc", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", + "outputs": 1, + "x": 230, + "y": 1400, + "wires": [ + [ + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" + ] + ] + }, + { + "id": "f34de19d4cf810a9", + "type": "comment", + "z": "e43a27722b508115", + "name": "Motor", + "info": "", + "x": 90, + "y": 1740, + "wires": [] + }, + { + "id": "26c2b58e21f97475", + "type": "comment", + "z": "e43a27722b508115", + "name": "Camera", + "info": "", + "x": 90, + "y": 2500, + "wires": [] + }, + { + "id": "a8ec972bad47a9a8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Pinout", + "info": "", + "x": 90, + "y": 2960, + "wires": [] + }, + { + "id": "b03e8b51187e88eb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "Rotor_delay (ms)", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 16, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 450, + "y": 2100, + "wires": [ + [ + "11fd3363416433f9" + ] + ] + }, + { + "id": "6aae9d4fddf08cc0", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt delay", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.01", + "max": "0.2", + "step": "0.005", + "className": "", + "x": 420, + "y": 2340, + "wires": [ + [ + "e50492d1e18f43c6" + ] + ] + }, + { + "id": "543e1690693acbeb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_acc", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 18, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 420, + "y": 2140, + "wires": [ + [ + "e8b24efb0f30288e" + ] + ] + }, + { + "id": "9a56c087d941f1da", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_accramp", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 20, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "100", + "max": "5000", + "step": "100", + "className": "", + "x": 440, + "y": 2180, + "wires": [ + [ + "29f576be9e292232" + ] + ] + }, + { + "id": "dfdebe10dbf0e198", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotor_stepsperrotation", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 14, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 460, + "y": 2060, + "wires": [ + [ + "78e256083f59f66f" + ] + ] + }, + { + "id": "af8dfe78cbd0c301", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, + "width": 3, + "height": 1, + "name": "rotor_acc_label", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2140, + "wires": [] + }, + { + "id": "ee4b8908a5b83880", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, + "width": 3, + "height": 1, + "name": "rotor_accramp_label", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 800, + "y": 2180, + "wires": [] + }, + { + "id": "c4deaa38c1b0adbf", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, + "width": 3, + "height": 1, + "name": "rotor_delay_label", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 790, + "y": 2100, + "wires": [] + }, + { + "id": "baec873a95fff48a", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, + "width": 3, + "height": 1, + "name": "rotor_steps_rotation_label", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 810, + "y": 2060, + "wires": [] + }, + { + "id": "355e89ab4e5484e4", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 1, + "width": 6, + "height": 1, + "name": "tt", + "label": "TURNTABLE", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 2300, + "wires": [] + }, + { + "id": "10687d331a732790", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_acc", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0.1", + "max": "2", + "step": "0.1", + "className": "", + "x": 410, + "y": 2380, + "wires": [ + [ + "af88b9da72917d62" + ] + ] + }, + { + "id": "721b9680a3fa460e", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_accramp", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "500", + "step": "1", + "className": "", + "x": 430, + "y": 2420, + "wires": [ + [ + "b1b4678827d3a6dd" + ] + ] + }, + { + "id": "c6642c7470d3820c", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "tt_stepsperrotation", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 450, + "y": 2300, + "wires": [ + [ + "eef89545ec0f6aa8" + ] + ] + }, + { + "id": "18e5918748660109", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 10, + "width": 3, + "height": 1, + "name": "tt_accramp_label", + "label": "Acceleration ramp", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2420, + "wires": [] + }, + { + "id": "8e805244dc1899e8", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 4, + "width": 3, + "height": 1, + "name": "tt_stepsperrotation_label", + "label": "Steps per Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 810, + "y": 2300, + "wires": [] + }, + { + "id": "a09e5fbea861bfb1", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 8, + "width": 3, + "height": 1, + "name": "tt_acc_label", + "label": "Acceleration", + "format": "", + "layout": "row-left", + "className": "", + "x": 770, + "y": 2380, + "wires": [] + }, + { + "id": "7b06448b3b222011", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 6, + "width": 3, + "height": 1, + "name": "tt_delay_label", + "label": "Delay", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2340, + "wires": [] + }, + { + "id": "0dfc86d90258f9bb", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 22, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 430, + "y": 2220, + "wires": [ + [ + "c4b5a38c5c1df3d2" + ] + ] + }, + { + "id": "9319d7d4f34c6d22", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, + "width": 3, + "height": 1, + "name": "rotor_angle_label", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 790, + "y": 2220, + "wires": [] + }, + { + "id": "1610895f430b9aca", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_angle", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "180", + "step": "1", + "className": "", + "x": 420, + "y": 2460, + "wires": [ + [ + "0f3367983bb8e159" + ] + ] + }, + { + "id": "96a9febc0928b6f0", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 12, + "width": 3, + "height": 1, + "name": "tt_angle_label", + "label": "Manual angle", + "format": "", + "layout": "row-spread", + "className": "", + "x": 780, + "y": 2460, + "wires": [] + }, + { + "id": "e2c5ea8c16a5ea32", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, + "width": 6, + "height": 1, + "name": "rotor", + "label": "ROTOR", + "format": "", + "layout": "row-center", + "className": "", + "x": 90, + "y": 1820, + "wires": [] + }, + { + "id": "277037c4716d85bf", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "tt_dir", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 410, + "y": 2500, + "wires": [ + [ + "c9d2e31514def4fc" + ] + ] + }, + { + "id": "1361134e9847f003", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_dir", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 24, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "1", + "className": "", + "x": 420, + "y": 2260, + "wires": [ + [ + "523717b0f218a5fd" + ] + ] + }, + { + "id": "6b0d58943ecb8bb2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 14, + "width": 3, + "height": 1, + "name": "tt_dir_label", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 770, + "y": 2500, + "wires": [] + }, + { + "id": "08f93dd2aeedb391", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, + "width": 3, + "height": 1, + "name": "rotor_dir_label", + "label": "Direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 780, + "y": 2260, + "wires": [] + }, + { + "id": "46b91bef44714366", + "type": "link in", + "z": "e43a27722b508115", + "name": "advanced settings", + "links": [ + "8750ad979e9ea246" + ], + "x": 95, + "y": 100, + "wires": [ + [ + "89eedf29b404f750" + ] + ] + }, + { + "id": "8750ad979e9ea246", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "46b91bef44714366" + ], + "x": 955, + "y": 480, + "wires": [] + }, + { + "id": "2522f888dc58972f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_before", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 7, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 450, + "y": 2600, + "wires": [ + [ + "5c752757090c49d2" + ] + ] + }, + { + "id": "30e8df3d616512d8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_gain", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 11, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "10", + "step": "0.1", + "className": "", + "x": 420, + "y": 2640, + "wires": [ + [ + "a1769f0277834f6d" + ] + ] + }, + { + "id": "d855d926df89d65b", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_contrast", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 13, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2760, + "wires": [ + [ + "1a8b0ba21b4f3005", + "654bc70a18820828" + ] + ] + }, + { + "id": "7617517dc8ba2859", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_saturation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 15, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "5", + "step": "0.1", + "className": "", + "x": 420, + "y": 2800, + "wires": [ + [ + "dc8fc962ff7d594b", + "e64feb03a791ca33" + ] + ] + }, + { + "id": "cbaa23c34e10fae1", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_jpeg_q", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 3, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "1", + "max": "100", + "step": "1", + "className": "", + "x": 410, + "y": 2840, + "wires": [ + [ + "00e7836ccb3c4d0c" + ] + ] + }, + { + "id": "bbe443b039a14e21", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, + "width": 3, + "height": 1, + "name": "delay_before", + "label": "Delay before", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2600, + "wires": [] + }, + { + "id": "d320ed3d701e6cc2", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, + "width": 3, + "height": 1, + "name": "gain", + "label": "Gain", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2640, + "wires": [] + }, + { + "id": "f5834dd4646c8af9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, + "width": 3, + "height": 1, + "name": "contrast", + "label": "Contrast", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2760, + "wires": [] + }, + { + "id": "ae9a4e19469813ef", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, + "width": 3, + "height": 1, + "name": "saturation", + "label": "Saturation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2800, + "wires": [] + }, + { + "id": "bd629d0d31233c8b", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 2, + "width": 3, + "height": 1, + "name": "jpegQ", + "label": "Jpeg Quality", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 2840, + "wires": [] + }, + { + "id": "e89f61dbe6a6cffe", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ext", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 3, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3000, + "wires": [ + [ + "885bc559fafec5f2" + ] + ] + }, + { + "id": "ece38cb172a12d75", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 2, + "width": 4, + "height": 1, + "name": "ext", + "label": "External Camera", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3000, + "wires": [] + }, + { + "id": "70014da0b6ab6698", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3040, + "wires": [ + [ + "f70321c96bf81360" + ] + ] + }, + { + "id": "29634ea5f6d666df", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 4, + "width": 4, + "height": 1, + "name": "light1", + "label": "Light 1", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3040, + "wires": [] + }, + { + "id": "2544963852c6881a", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "light2", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 7, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3080, + "wires": [ + [ + "95e1603bbd06a69d" + ] + ] + }, + { + "id": "27903533cd85a59e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 6, + "width": 4, + "height": 1, + "name": "light2", + "label": "Light 2", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3080, + "wires": [] + }, + { + "id": "a1394401246eb735", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotordir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 9, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3120, + "wires": [ + [ + "a8f92ea6bf394640" + ] + ] + }, + { + "id": "bc0aa4bacdfa94ea", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 8, + "width": 4, + "height": 1, + "name": "rotordir", + "label": "Rotor direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3120, + "wires": [] + }, + { + "id": "f15ca4518b5f223e", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotorstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 11, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3160, + "wires": [ + [ + "06397bb46b3bb541" + ] + ] + }, + { + "id": "0d2924b160e7e383", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 10, + "width": 4, + "height": 1, + "name": "rotorstep", + "label": "Rotor step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3160, + "wires": [] + }, + { + "id": "49900bb9047dd965", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "rotoren", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 13, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3200, + "wires": [ + [ + "687dcdc1ede11700" + ] + ] + }, + { + "id": "a4d743ca73ee1622", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 12, + "width": 4, + "height": 1, + "name": "rotoren", + "label": "Rotor enable", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3200, + "wires": [] + }, + { + "id": "5a90224dc998b417", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttdir", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 15, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3240, + "wires": [ + [ + "e220740c0d38ccb0" + ] + ] + }, + { + "id": "67dc1b544c4ddf9f", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 14, + "width": 4, + "height": 1, + "name": "ttdir", + "label": "Turntable direction", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3240, + "wires": [] + }, + { + "id": "d2364ab09627fe94", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "ttstep", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 17, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 390, + "y": 3280, + "wires": [ + [ + "79d7e5a705ab813a" + ] + ] + }, + { + "id": "145b67ac40721ba6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 16, + "width": 4, + "height": 1, + "name": "ttstep", + "label": "Turntable step", + "format": "", + "layout": "row-spread", + "className": "", + "x": 730, + "y": 3280, + "wires": [] + }, + { + "id": "eef25405472acfee", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "endstop1", + "label": "", + "tooltip": "", + "group": "70d0be671bf03ca7", + "order": 19, + "width": 2, + "height": 1, + "passthru": false, + "mode": "number", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 400, + "y": 3320, + "wires": [ + [ + "12d20f2274bcc511" + ] + ] + }, + { + "id": "35eb252a41413531", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 18, + "width": 4, + "height": 1, + "name": "endstop1", + "label": "Endstop Rotor", + "format": "", + "layout": "row-spread", + "className": "", + "x": 740, + "y": 3320, + "wires": [] + }, + { + "id": "5fcef1cb2e9e4788", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "confirm", + "x": 680, + "y": 480, + "wires": [ + [ + "29745a36fc157f3f" + ] + ] + }, + { + "id": "f06a7bcad524e9f9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "msg", + "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", + "outputs": 1, + "x": 530, + "y": 480, + "wires": [ + [ + "5fcef1cb2e9e4788" + ] + ] + }, + { + "id": "f455fb39039617ae", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_rotation", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 5, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "270", + "step": "90", + "className": "", + "x": 410, + "y": 2880, + "wires": [ + [ + "3019576de193d9d6" + ] + ] + }, + { + "id": "fdfbc900fe424eb9", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, + "width": 3, + "height": 1, + "name": "cam_rot", + "label": "Image Rotation", + "format": "", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 2880, + "wires": [] + }, + { + "id": "c3699d6b9664ccca", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2060, + "wires": [ + [ + "dfdebe10dbf0e198" + ] + ] + }, + { + "id": "78e256083f59f66f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2060, + "wires": [ + [] + ] + }, + { + "id": "0f9141b401322374", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2180, + "wires": [ + [ + "9a56c087d941f1da" + ] + ] + }, + { + "id": "29f576be9e292232", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2180, + "wires": [ + [] + ] + }, + { + "id": "23e3099b34c4e475", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2220, + "wires": [ + [ + "0dfc86d90258f9bb" + ] + ] + }, + { + "id": "c4b5a38c5c1df3d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2220, + "wires": [ + [] + ] + }, + { + "id": "79a14162ac805fac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2260, + "wires": [ + [ + "1361134e9847f003" + ] + ] + }, + { + "id": "523717b0f218a5fd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2260, + "wires": [ + [] + ] + }, + { + "id": "f5cf780f3fa8997e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2100, + "wires": [ + [ + "b03e8b51187e88eb" + ] + ] + }, + { + "id": "11fd3363416433f9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2100, + "wires": [ + [] + ] + }, + { + "id": "02060b3f3b294563", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2140, + "wires": [ + [ + "543e1690693acbeb" + ] + ] + }, + { + "id": "e8b24efb0f30288e", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2140, + "wires": [ + [] + ] + }, + { + "id": "de1ad8b27b72a5ac", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nvar steps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2300, + "wires": [ + [ + "c6642c7470d3820c" + ] + ] + }, + { + "id": "ed4d587cb4feb064", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2420, + "wires": [ + [ + "721b9680a3fa460e" + ] + ] + }, + { + "id": "5b02160c33605ae7", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2460, + "wires": [ + [ + "1610895f430b9aca" + ] + ] + }, + { + "id": "304c135ec09801e3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2500, + "wires": [ + [ + "277037c4716d85bf" + ] + ] + }, + { + "id": "a91dcbe0f9a2416a", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2340, + "wires": [ + [ + "6aae9d4fddf08cc0" + ] + ] + }, + { + "id": "6b2eb1cb95e573f9", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2380, + "wires": [ + [ + "10687d331a732790" + ] + ] + }, + { + "id": "eef89545ec0f6aa8", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2300, + "wires": [ + [] + ] + }, + { + "id": "b1b4678827d3a6dd", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2420, + "wires": [ + [] + ] + }, + { + "id": "0f3367983bb8e159", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2460, + "wires": [ + [] + ] + }, + { + "id": "c9d2e31514def4fc", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2500, + "wires": [ + [] + ] + }, + { + "id": "e50492d1e18f43c6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2340, + "wires": [ + [] + ] + }, + { + "id": "af88b9da72917d62", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2380, + "wires": [ + [] + ] + }, + { + "id": "43fe948b3e7234e2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2600, + "wires": [ + [ + "2522f888dc58972f" + ] + ] + }, + { + "id": "5c752757090c49d2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2600, + "wires": [ + [] + ] + }, + { + "id": "435681b3f7625a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2640, + "wires": [ + [ + "30e8df3d616512d8" + ] + ] + }, + { + "id": "a1769f0277834f6d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2640, + "wires": [ + [] + ] + }, + { + "id": "1de07c7d285cbaf3", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2760, + "wires": [ + [ + "d855d926df89d65b" + ] + ] + }, + { + "id": "1a8b0ba21b4f3005", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2760, + "wires": [ + [] + ] + }, + { + "id": "ebc9e283468eda31", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2800, + "wires": [ + [ + "7617517dc8ba2859" + ] + ] + }, + { + "id": "dc8fc962ff7d594b", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2800, + "wires": [ + [] + ] + }, + { + "id": "60d641613527c736", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2840, + "wires": [ + [ + "cbaa23c34e10fae1" + ] + ] + }, + { + "id": "00e7836ccb3c4d0c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2840, + "wires": [ + [] + ] + }, + { + "id": "7f24c0c34a88ba04", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2880, + "wires": [ + [ + "f455fb39039617ae" + ] + ] + }, + { + "id": "3019576de193d9d6", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2880, + "wires": [ + [] + ] + }, + { + "id": "77bb7dc529d63a7e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3000, + "wires": [ + [ + "e89f61dbe6a6cffe" + ] + ] + }, + { + "id": "885bc559fafec5f2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3000, + "wires": [ + [] + ] + }, + { + "id": "cc6dabe017a9c8a8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3320, + "wires": [ + [ + "eef25405472acfee" + ] + ] + }, + { + "id": "12d20f2274bcc511", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3320, + "wires": [ + [] + ] + }, + { + "id": "dcb9fed8122759fd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3040, + "wires": [ + [ + "70014da0b6ab6698" + ] + ] + }, + { + "id": "f70321c96bf81360", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3040, + "wires": [ + [] + ] + }, + { + "id": "013d2057c2347a62", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3080, + "wires": [ + [ + "2544963852c6881a" + ] + ] + }, + { + "id": "95e1603bbd06a69d", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3080, + "wires": [ + [] + ] + }, + { + "id": "f88bbf11d5aa9a14", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3120, + "wires": [ + [ + "a1394401246eb735" + ] + ] + }, + { + "id": "a8f92ea6bf394640", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3120, + "wires": [ + [] + ] + }, + { + "id": "301af70731e096e5", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3160, + "wires": [ + [ + "f15ca4518b5f223e" + ] + ] + }, + { + "id": "06397bb46b3bb541", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3160, + "wires": [ + [] + ] + }, + { + "id": "0456a9ec4c236c9e", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3200, + "wires": [ + [ + "49900bb9047dd965" + ] + ] + }, + { + "id": "687dcdc1ede11700", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3200, + "wires": [ + [] + ] + }, + { + "id": "09d37ba08ec0f163", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3240, + "wires": [ + [ + "5a90224dc998b417" + ] + ] + }, + { + "id": "37d954a4cf7e87ea", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 3280, + "wires": [ + [ + "d2364ab09627fe94" + ] + ] + }, + { + "id": "e220740c0d38ccb0", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3240, + "wires": [ + [] + ] + }, + { + "id": "79d7e5a705ab813a", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 590, + "y": 3280, + "wires": [ + [] + ] + }, + { + "id": "22ef66b0e2058be2", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 360, + "wires": [ + [ + "cb3437ec113e1b6f" + ] + ] + }, + { + "id": "9ce01c8ba97932c1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 400, + "wires": [ + [ + "60fd0adce1cfeb82" + ] + ] + }, + { + "id": "81356177176eebcf", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 480, + "wires": [ + [ + "f6d6cc35679ede63" + ] + ] + }, + { + "id": "b78346ca3ce70c68", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 320, + "wires": [ + [ + "f0d8dbcca76a1926" + ] + ] + }, + { + "id": "e95b86cbac1b03b9", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "3e4c15d7b538f816", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 670, + "y": 1540, + "wires": [ + [ + "3bf622f344172721" + ] + ] + }, + { + "id": "0f0871baf322b6d0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1820, + "wires": [ + [ + "6ebd15c61a5ca891" + ] + ] + }, + { + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin_label", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1820, + "wires": [ + [] + ] + }, + { + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, + "wires": [ + [ + "acd10a4c99ee8063" + ] + ] + }, + { + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, + "wires": [ + [ + "031d7697768d0e77" + ] + ] + }, + { + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, + "wires": [ + [ + "be1954dd71d2c94c" + ] + ] + }, + { + "id": "edb1c8fae8b65c82", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1860, + "wires": [ + [ + "3ad0f0f206e4a873" + ] + ] + }, + { + "id": "031d7697768d0e77", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1860, + "wires": [ + [] + ] + }, + { + "id": "462a8f3ca75fc3c8", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1900, + "wires": [ + [ + "3b6d759ed5be647f" + ] + ] + }, + { + "id": "be1954dd71d2c94c", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1900, + "wires": [ + [] + ] + }, + { + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax_label", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart_label", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, + "wires": [ + [ + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88", + "53681e53353db898" + ] + ] + }, + { + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, + "y": 940, + "wires": [ + [ + "ded3086945a6d4b5", + "6ea3cdab41f20f92" + ] + ] + }, + { + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, + "wires": [ + [ + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd", + "a74d78a1d186a833" + ] + ] + }, + { + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2540, + "wires": [ + [ + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" + ] + ] + }, + { + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3000, + "wires": [ + [ + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8" + ] + ] + }, + { + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 620, + "wires": [ + [ + "53e6681d7254d484" + ] + ] + }, + { + "id": "53e6681d7254d484", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 270, + "y": 620, + "wires": [ + [ + "c11e79cfa7bc10b7" + ] + ] + }, + { + "id": "c11e79cfa7bc10b7", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 620, + "wires": [ + [ + "307782d10c1acdaf" + ] + ] + }, + { + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 620, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "cca3300a8f0daf4d", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", + "order": 1, + "width": 6, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 750, + "y": 180, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "654bc70a18820828", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_contrast?contrast=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2720, + "wires": [ + [] + ] + }, + { + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/v1/camera/picam2_saturation?saturation=\" + str(msg['payload']))", + "outputs": 1, + "x": 660, + "y": 2680, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2560, + "wires": [ + [ + "e612073aded01a8f" + ] + ] + }, + { + "id": "0d92559980944ae3", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, + "width": 3, + "height": 1, + "name": "delay_after", + "label": "Delay after", + "format": "", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 2560, + "wires": [] + }, + { + "id": "6281b2e6e081104d", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2560, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 620, + "y": 2560, + "wires": [ + [] + ] + }, + { + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 560, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 560, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 210, + "y": 980, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 220, + "y": 1020, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, + "className": "", + "topicType": "str", + "x": 240, + "y": 1060, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] + }, + { + "id": "a7d233f984009e2e", + "type": "function", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 440, + "y": 980, + "wires": [ + [ + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" + ] + ] + }, + { + "id": "65518f3d4e3095e5", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 1", + "links": [ + "200d4b9951b6e066" + ], + "x": 85, + "y": 980, + "wires": [ + [ + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" + ] + ] + }, + { + "id": "9b851aa999e86fd7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", + "outputs": 1, + "x": 670, + "y": 980, + "wires": [ + [ + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" + ] + ] + }, + { + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 870, + "y": 980, + "wires": [ + [] + ] + }, + { + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, + "wires": [] + }, + { + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", + "links": [ + "592ec13d8f8923a9" + ], + "x": 815, + "y": 1020, + "wires": [] + }, + { + "id": "1eef47e0074545a9", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, + "wires": [ + [ + "c994c779e4bad800", + "36890eb99a2ca1cf" + ], + [] + ] + }, + { + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, + "wires": [ + [ + "1eef47e0074545a9" + ] + ] + }, + { + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", + "name": "", + "x": 670, + "y": 1020, + "wires": [] + }, + { + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, + "wires": [] + }, + { + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, + "wires": [ + [ + "85ad07b8f973bbe2" + ] + ] + }, + { + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "rotor_endstop_angle_label", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 820, + "y": 2020, + "wires": [] + }, + { + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, + "wires": [ + [] + ] + }, + { + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, + "wires": [ + [ + "6b7245c3dcb694c8" + ] + ] + }, + { + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, + "wires": [ + [ + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" + ] + ] + }, + { + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, + "wires": [ + [ + "253feafa5a2f8b1d" + ] + ] + }, + { + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, + "wires": [ + [] + ] + }, + { + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_enable_endstop_label", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 820, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 450, + "y": 1980, + "wires": [ + [ + "69516440e3997111", + "f036424d79645761" + ] + ] + }, + { + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, + "wires": [ + [ + "eefed04c25e3e4d6" + ] + ] + }, + { + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, + "wires": [ + [ + "2aaf7c7f0f0c146f" + ] + ] + }, + { + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", + "outputs": 1, + "x": 660, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3560, + "wires": [ + [ + "d0a1a4947a1137ca" + ] + ] + }, + { + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 540, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] + }, + { + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, + "wires": [ + [] + ] + }, + { + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3640, + "wires": [ + [ + "b5aba11033c5f952" + ] + ] + }, + { + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, + { + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, + { + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "e98c1b83744bb863", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Delete Aborted", + "tooltip": "Delete aborted photosets", + "group": "d324f0b852c2df0a", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 420, + "y": 520, + "wires": [ + [ + "7438a5bf5fcddec4" + ] + ] + }, + { + "id": "7438a5bf5fcddec4", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "delete_aborted", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('delete_aborted'):\n save('delete_aborted', state)\n", + "outputs": 1, + "x": 600, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "53681e53353db898", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'delete_aborted'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 520, + "wires": [ + [ + "e98c1b83744bb863" + ] + ] + }, + { + "id": "48386fdb54980ec7", + "type": "comment", + "z": "e43a27722b508115", + "name": "Shield", + "info": "", + "x": 90, + "y": 3760, + "wires": [] + }, + { + "id": "fbc5fc2e65311f8b", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 3", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3840, + "wires": [ + [ + "5618e266f6966ae6" + ] + ] + }, + { + "id": "5618e266f6966ae6", + "type": "function", + "z": "e43a27722b508115", + "name": "loadl", + "func": "var file = 'shield_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath + file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 170, + "y": 3840, + "wires": [ + [ + "c97113d841391e40" + ] + ] + }, + { + "id": "c97113d841391e40", + "type": "ui_dropdown", + "z": "e43a27722b508115", + "name": "", + "label": "Shield Type", + "tooltip": "", + "place": "Select option", + "group": "0b244f698c7ac9a2", + "order": 0, + "width": 0, + "height": 0, + "passthru": true, + "multiple": false, + "options": [ + { + "label": "Green", + "value": "green", + "type": "str" + }, + { + "label": "Black", + "value": "black", + "type": "str" + } + ], + "payload": "", + "topic": "payload", + "topicType": "msg", + "className": "", + "x": 310, + "y": 3840, + "wires": [ + [ + "2b639346c1b56578" + ] + ] + }, + { + "id": "2b639346c1b56578", + "type": "function", + "z": "e43a27722b508115", + "name": "function 2", + "func": "let fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar file = 'shield_type';\nconst current_shield = fs.readFileSync(filepath + file, 'utf8');\n\nvar current_choice = msg.payload\n\nif (current_choice != current_shield) {\n \n switch (current_choice) {\n case \"green\":\n fs.writeFile(filepath + 'pin_external', String(10), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(17), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(9), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(11), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(14), err => {\n if (err) {\n return\n }\n });\n break;\n case \"black\":\n fs.writeFile(filepath + 'pin_external', String(5), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight1', String(24), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_ringlight2', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_dir', String(23), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_step', String(27), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_enable', String(22), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_dir', String(6), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_tt_step', String(26), err => {\n if (err) {\n return\n }\n });\n fs.writeFile(filepath + 'pin_rotor_endstop', String(17), err => {\n if (err) {\n return\n }\n });\n break;\n case \"custom\":\n break;\n }\n\n fs.writeFile(filepath + file, current_choice, err => {\n if (err) {\n return\n }\n });\n}\n\nmsg.status = 'The new ' + current_choice + ' shield has been configured'\nmsg.topic = msg.status\nmsg.payload = 'Do you want to reboot now to apply the changes?'\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 460, + "y": 3840, + "wires": [ + [ + "137f032887544d74" + ] + ] + }, + { + "id": "137f032887544d74", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "prompt", + "displayTime": "3", + "highlight": "", + "sendall": false, + "outputs": 1, + "ok": "OK", + "cancel": "Cancel", + "raw": true, + "className": "", + "topic": "", + "name": "Reboot", + "x": 600, + "y": 3840, + "wires": [ + [ + "d2db49796fe0da79", + "d0d6820224b0ab0f" + ] + ] + }, + { + "id": "d2db49796fe0da79", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "print(msg['payload'])\nreturn msg", + "outputs": 1, + "x": 790, + "y": 3840, + "wires": [ + [] + ] + }, + { + "id": "d0d6820224b0ab0f", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 6", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 780, + "y": 3720, + "wires": [] + }, + { + "id": "a74d78a1d186a833", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotate_tt_first'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1760, + "wires": [ + [ + "4e1b38e60f4179b0" + ] + ] + }, + { + "id": "4e1b38e60f4179b0", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotate_tt_first", + "label": "", + "tooltip": "", + "group": "38d121ea5b2bd77d", + "order": 3, + "width": "3", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 430, + "y": 1760, + "wires": [ + [ + "0e14711b77c43c23" + ] + ] + }, + { + "id": "0e14711b77c43c23", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotate_tt_first'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1760, + "wires": [ + [] + ] + }, + { + "id": "b1d13cc1ebec82d7", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "38d121ea5b2bd77d", + "order": 2, + "width": 3, + "height": 1, + "name": "rotate_tt_first_label", + "label": "Rotate turntable first", + "format": "", + "layout": "row-left", + "className": "", + "x": 790, + "y": 1760, + "wires": [] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'stable'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/2024-11S/update/2024-11S'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] + }, + { + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, + "wires": [ + [ + "4ce127c61c3c5966", + "beacc3dc5398fa79" + ] + ] + }, + { + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", + "outputs": 1, + "x": 290, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "beacc3dc5398fa79", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "b0629875a30ae1d7", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nopenscan_version = load_str('openscan_version')\nopenscan_branch = load_str('openscan_branch')\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/' + openscan_version + '/update/' + openscan_version\n\nupdatepath = '/home/pi/OpenScan/updates/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + '/update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\nmsg['openscan_version'] = openscan_version\nmsg['openscan_branch'] = openscan_branch\nmsg['url'] = url\nreturn msg, msg", + "outputs": 2, + "x": 390, + "y": 540, + "wires": [ + [ + "1bbe2d769f42c313" + ], + [ + "fefe45404bdb19c4" + ] + ] + }, + { + "id": "c7b6d05a62172432", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "Status:", + "format": "{{msg.status}}", + "layout": "row-spread", + "className": "", + "x": 210, + "y": 400, + "wires": [] + }, + { + "id": "fefe45404bdb19c4", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "check files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nopenscan_branch = msg['openscan_branch']\nopenscan_version = msg['openscan_version']\nurl = msg['url']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[openscan_branch]:\n filepath = msg[openscan_branch][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[openscan_branch][i]['filesize2'] = filesize\n if filesize == msg[openscan_branch][i]['filesize']:\n msg[openscan_branch][i]['update'] = False\n continue\n msg[openscan_branch][i]['update'] = True\n\n counter += 1\n\nmsg['openscan_branch'] = openscan_branch\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "outputs": 1, + "x": 550, + "y": 560, + "wires": [ + [ + "1bbe2d769f42c313", + "ae92a328af306ebb" + ] + ] + }, + { + "id": "d0104e0163745993", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 115, + "y": 440, + "wires": [ + [ + "ec30638407332e43", + "49f1ecb29a3f84f4" + ] + ] + }, + { + "id": "ec30638407332e43", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadS", + "func": "var file = 'openscan_branch'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 370, + "y": 420, + "wires": [ + [ + "2852023f3aa8db10" + ] + ] + }, + { + "id": "2852023f3aa8db10", + "type": "ui_dropdown", + "z": "a5557543ccff5889", + "name": "", + "label": "", + "tooltip": "", + "place": "Select option", + "group": "ddbd496e.93a288", + "order": 5, + "width": 2, + "height": 1, + "passthru": false, + "multiple": false, + "options": [ + { + "label": "stable", + "value": "stable", + "type": "str" + }, + { + "label": "beta", + "value": "beta", + "type": "str" + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" + } + ], + "payload": "", + "topic": "topic", + "topicType": "msg", + "className": "", + "x": 500, + "y": 420, + "wires": [ + [ + "1e10b387ee30c486" + ] + ] + }, + { + "id": "1e10b387ee30c486", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'openscan_branch'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 420, + "wires": [ + [] + ] + }, + { + "id": "274129c51b0b87ef", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "ddbd496e.93a288", + "order": 4, + "width": 4, + "height": 1, + "name": "", + "label": "Branch: ", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 760, + "y": 420, + "wires": [] + }, + { + "id": "51cd8c8643e6b46a", + "type": "ui_switch", + "z": "a5557543ccff5889", + "name": "", + "label": "Auto-check update availability", + "tooltip": "", + "group": "ddbd496e.93a288", + "order": 6, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 450, + "y": 480, + "wires": [ + [ + "1ab4c6b4b232a022" + ] + ] + }, + { + "id": "1ab4c6b4b232a022", + "type": "function", + "z": "a5557543ccff5889", + "name": "write", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 650, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "ae92a328af306ebb", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "NO", + "cancel": "YES", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 710, + "y": 560, + "wires": [ + [ + "2de63e8e3ae5fb0c", + "929281fef53e09f8" + ] + ] + }, + { + "id": "cbd0afc4aa7b302a", + "type": "link in", + "z": "a5557543ccff5889", + "name": "update status", + "links": [ + "1bbe2d769f42c313", + "42061b28cff81f99" + ], + "x": 115, + "y": 400, + "wires": [ + [ + "c7b6d05a62172432", + "c94623ddd9d95f78" + ] + ] + }, + { + "id": "1bbe2d769f42c313", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 665, + "y": 520, + "wires": [] + }, + { + "id": "7cf60615d93e696b", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 7, + "width": 6, + "height": 1, + "passthru": false, + "label": "Check Updates", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 180, + "y": 560, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "2de63e8e3ae5fb0c", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "download files", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\nopenscan_version = load_str('openscan_version')\n\nopenscan_branch = msg['openscan_branch']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = msg['url']\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[openscan_branch]:\n if msg[openscan_branch][i]['update'] == False:\n continue\n \n filepath = msg[openscan_branch][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + '/' + msg[openscan_branch][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[openscan_branch][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[openscan_branch][i]['dst'])\n \n if msg[openscan_branch][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "outputs": 1, + "x": 880, + "y": 560, + "wires": [ + [ + "42061b28cff81f99", + "fe3a855fee9e28c6" + ] + ] + }, + { + "id": "929281fef53e09f8", + "type": "function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 850, + "y": 520, + "wires": [ + [ + "42061b28cff81f99" + ] + ] + }, + { + "id": "42061b28cff81f99", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "cbd0afc4aa7b302a" + ], + "x": 995, + "y": 520, + "wires": [] + }, + { + "id": "49f1ecb29a3f84f4", + "type": "function", + "z": "a5557543ccff5889", + "name": "loadB", + "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 217, + "y": 508, + "wires": [ + [ + "b0629875a30ae1d7", + "51cd8c8643e6b46a" + ] + ] + }, + { + "id": "fe3a855fee9e28c6", + "type": "link out", + "z": "a5557543ccff5889", + "name": "", + "mode": "link", + "links": [ + "9bb0adbd716ce347", + "01c882fcc51b349c" + ], + "x": 995, + "y": 560, + "wires": [] + }, + { + "id": "5e7d5e4335d37794", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 95, + "y": 700, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "2bb5fe78e09fec8a", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "msg", + "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", + "outputs": 1, + "x": 210, + "y": 700, + "wires": [ + [ + "dbc77052ac950624", + "d97c3068ef5fef96", + "73a3b828f862312b", + "901e31453b2bdff8", + "f983854748ee4763", + "5347c7c517f5e8c7", + "3a5016f7003cd72c", + "6d720c4a4ecd9475", + "6438b7d060a70d81" + ] + ] + }, + { + "id": "d97c3068ef5fef96", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "OS:", + "format": "{{msg.os}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 740, + "wires": [] + }, + { + "id": "73a3b828f862312b", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 8, + "width": 0, + "height": 0, + "name": "", + "label": "Flask:", + "format": "{{msg.flask}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 780, + "wires": [] + }, + { + "id": "dbc77052ac950624", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 1, + "width": 0, + "height": 0, + "name": "", + "label": "Device:", + "format": "{{msg.device}}", + "layout": "row-spread", + "className": "", + "x": 500, + "y": 700, + "wires": [] + }, + { + "id": "3f42560297fe6978", + "type": "ui_template", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "name": "Download LOG", + "order": 9, + "width": 6, + "height": 1, + "format": "\n
Download error log\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 180, + "y": 1060, + "wires": [ + [] + ] + }, + { + "id": "c94623ddd9d95f78", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "get update", + "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", + "outputs": 1, + "x": 210, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "39a502b38837273d", + "type": "link in", + "z": "a5557543ccff5889", + "name": "", + "links": [ + "1e7457ea9c2c5e09" + ], + "x": 245, + "y": 600, + "wires": [ + [ + "b0629875a30ae1d7" + ] + ] + }, + { + "id": "901e31453b2bdff8", + "type": "delay", + "z": "a5557543ccff5889", + "name": "", + "pauseType": "delay", + "timeout": "10", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, + "outputs": 1, + "x": 220, + "y": 740, + "wires": [ + [ + "2bb5fe78e09fec8a" + ] + ] + }, + { + "id": "f983854748ee4763", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 3, + "width": 0, + "height": 0, + "name": "", + "label": "", + "format": "{{msg.osdate}}", + "layout": "row-spread", + "className": "", + "x": 490, + "y": 820, + "wires": [] + }, + { + "id": "5347c7c517f5e8c7", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 4, + "width": 0, + "height": 0, + "name": "", + "label": "CPU temp:", + "format": "{{msg.temp}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 860, + "wires": [] + }, + { + "id": "3a5016f7003cd72c", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 5, + "width": 0, + "height": 0, + "name": "", + "label": "CPU memory:", + "format": "{{msg.cpu}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 900, + "wires": [] + }, + { + "id": "6d720c4a4ecd9475", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 6, + "width": 0, + "height": 0, + "name": "", + "label": "Swap memory:", + "format": "{{msg.swap}}", + "layout": "row-spread", + "className": "", + "x": 520, + "y": 940, + "wires": [] + }, + { + "id": "6438b7d060a70d81", + "type": "ui_text", + "z": "a5557543ccff5889", + "group": "3ce32450.e0cffc", + "order": 7, + "width": 0, + "height": 0, + "name": "", + "label": "Diskspace:", + "format": "{{msg.diskspace}}", + "layout": "row-spread", + "className": "", + "x": 510, + "y": 980, + "wires": [] + }, + { + "id": "8d012912f302be85", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "ddbd496e.93a288", + "order": 8, + "width": 6, + "height": 1, + "passthru": false, + "label": "Show Details/Changelog", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 210, + "y": 640, + "wires": [ + [ + "5242607a723cc628" + ] + ] + }, + { + "id": "5242607a723cc628", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "Changelog", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "outputs": 1, + "x": 430, + "y": 640, + "wires": [ + [ + "573722197b15bf84" + ] + ] + }, + { + "id": "573722197b15bf84", + "type": "ui_toast", + "z": "a5557543ccff5889", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 610, + "y": 640, + "wires": [ + [] + ] + }, + { + "id": "9b3e6a06c82a0f52", + "type": "link in", + "z": "87715429b0b1c9a3", + "name": "", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 55, + "y": 120, + "wires": [ + [ + "f128ca405d1e1e4d", + "07d7ce3dab5f1c11" + ] + ] + }, + { + "id": "cd0dc08fcb5968c8", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Successful Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 410, + "y": 100, + "wires": [] + }, + { + "id": "f128ca405d1e1e4d", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics*.json|grep -i \\\"aborted\\\":false|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Successful Scans", + "x": 210, + "y": 120, + "wires": [ + [ + "cd0dc08fcb5968c8" + ], + [], + [] + ] + }, + { + "id": "b91b4d65f2090793", + "type": "ui_text", + "z": "87715429b0b1c9a3", + "group": "ac59b8fb186de073", + "order": 0, + "width": 0, + "height": 0, + "name": "", + "label": "Aborted Scans", + "format": "{{msg.payload}}", + "layout": "row-spread", + "className": "", + "x": 400, + "y": 160, + "wires": [] + }, + { + "id": "07d7ce3dab5f1c11", + "type": "exec", + "z": "87715429b0b1c9a3", + "command": "cat /home/pi/OpenScan/statistics/statistics*.json|grep -i \\\"aborted\\\":true|wc -l", + "addpay": "", + "append": "", + "useSpawn": "false", + "timer": "", + "winHide": false, + "oldrc": false, + "name": "Aborted Scans", + "x": 200, + "y": 180, + "wires": [ + [ + "b91b4d65f2090793" + ], + [], + [] + ] + }, + { + "id": "5b3aa9a71591ba34", + "type": "comment", + "z": "87715429b0b1c9a3", + "name": "Statistics", + "info": "", + "x": 100, + "y": 40, + "wires": [] + } +] \ No newline at end of file diff --git a/update/2024-1o/stable/settings.js b/update/2024-1o/stable/settings.js new file mode 100644 index 0000000..357b02b --- /dev/null +++ b/update/2024-1o/stable/settings.js @@ -0,0 +1,512 @@ +/** + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT + * + * It can contain any valid JavaScript code that will get run when Node-RED + * is started. + * + * Lines that start with // are commented out. + * Each entry should be separated from the entries above and below by a comma ',' + * + * For more information about individual settings, refer to the documentation: + * https://nodered.org/docs/user-guide/runtime/configuration + * + * The settings are split into the following sections: + * - Flow File and User Directory Settings + * - Security + * - Server Settings + * - Runtime Settings + * - Editor Settings + * - Node Settings + * + **/ +process.env.HOSTNAME = require('os').hostname(); + +module.exports = { + +/******************************************************************************* + * Flow File and User Directory Settings + * - flowFile + * - credentialSecret + * - flowFilePretty + * - userDir + * - nodesDir + ******************************************************************************/ + + /** The file containing the flows. If not set, defaults to flows_.json **/ + flowFile: "flows.json", + + /** By default, credentials are encrypted in storage using a generated key. To + * specify your own secret, set the following property. + * If you want to disable encryption of credentials, set this property to false. + * Note: once you set this property, do not change it - doing so will prevent + * node-red from being able to decrypt your existing credentials and they will be + * lost. + */ + credentialSecret: false, + + /** By default, the flow JSON will be formatted over multiple lines making + * it easier to compare changes when using version control. + * To disable pretty-printing of the JSON set the following property to false. + */ + flowFilePretty: true, + + /** By default, all user data is stored in a directory called `.node-red` under + * the user's home directory. To use a different location, the following + * property can be used + */ + //userDir: '/home/nol/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + + /** Node-RED scans the `nodes` directory in the userDir to find local node files. + * The following property can be used to specify an additional directory to scan. + */ + //nodesDir: '/home/nol/.node-red/nodes', + +/******************************************************************************* + * Security + * - adminAuth + * - https + * - httpsRefreshInterval + * - requireHttps + * - httpNodeAuth + * - httpStaticAuth + ******************************************************************************/ + + /** To password protect the Node-RED editor and admin API, the following + * property can be used. See http://nodered.org/docs/security.html for details. + */ + //adminAuth: { + // type: "credentials", + // users: [{ + // username: "admin", + // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", + // permissions: "*" + // }] + //}, + + /** The following property can be used to enable HTTPS + * This property can be either an object, containing both a (private) key + * and a (public) certificate, or a function that returns such an object. + * See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener + * for details of its contents. + */ + + /** Option 1: static object */ + //https: { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + //}, + + /** Option 2: function that returns the HTTP configuration object */ + // https: function() { + // // This function should return the options object, or a Promise + // // that resolves to the options object + // return { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + // } + // }, + + /** If the `https` setting is a function, the following setting can be used + * to set how often, in hours, the function will be called. That can be used + * to refresh any certificates. + */ + //httpsRefreshInterval : 12, + + /** The following property can be used to cause insecure HTTP connections to + * be redirected to HTTPS. + */ + //requireHttps: true, + + /** To password protect the node-defined HTTP endpoints (httpNodeRoot), + * including node-red-dashboard, or the static content (httpStatic), the + * following properties can be used. + * The `pass` field is a bcrypt hash of the password. + * See http://nodered.org/docs/security.html#generating-the-password-hash + */ + //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + +/******************************************************************************* + * Server Settings + * - uiPort + * - uiHost + * - apiMaxLength + * - httpServerOptions + * - httpAdminRoot + * - httpAdminMiddleware + * - httpNodeRoot + * - httpNodeCors + * - httpNodeMiddleware + * - httpStatic + * - httpStaticRoot + ******************************************************************************/ + + /** the tcp port that the Node-RED web server is listening on */ + uiPort: process.env.PORT || 80, + + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. + * To listen on all IPv6 addresses, set uiHost to "::", + * The following property can be used to listen on a specific interface. For + * example, the following would only allow connections from the local machine. + */ + //uiHost: "127.0.0.1", + + /** The maximum size of HTTP request that will be accepted by the runtime api. + * Default: 5mb + */ + //apiMaxLength: '5mb', + + /** The following property can be used to pass custom options to the Express.js + * server used by Node-RED. For a full list of available options, refer + * to http://expressjs.com/en/api.html#app.settings.table + */ + //httpServerOptions: { }, + + /** By default, the Node-RED UI is available at http://localhost:1880/ + * The following property can be used to specify a different root path. + * If set to false, this is disabled. + */ + httpAdminRoot: '/editor', + + /** The following property can be used to add a custom middleware function + * in front of all admin http routes. For example, to set custom http + * headers. It can be a single function or an array of middleware functions. + */ + // httpAdminMiddleware: function(req,res,next) { + // // Set the X-Frame-Options header to limit where the editor + // // can be embedded + // //res.set('X-Frame-Options', 'sameorigin'); + // next(); + // }, + + + /** Some nodes, such as HTTP In, can be used to listen for incoming http requests. + * By default, these are served relative to '/'. The following property + * can be used to specifiy a different root path. If set to false, this is + * disabled. + */ + //httpNodeRoot: '/red-nodes', + + /** The following property can be used to configure cross-origin resource sharing + * in the HTTP nodes. + * See https://github.com/troygoode/node-cors#configuration-options for + * details on its contents. The following is a basic permissive set of options: + */ + //httpNodeCors: { + // origin: "*", + // methods: "GET,PUT,POST,DELETE" + //}, + + /** If you need to set an http proxy please set an environment variable + * called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. + * For example - http_proxy=http://myproxy.com:8080 + * (Setting it here will have no effect) + * You may also specify no_proxy (or NO_PROXY) to supply a comma separated + * list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk + */ + + /** The following property can be used to add a custom middleware function + * in front of all http in nodes. This allows custom authentication to be + * applied to all http in nodes, or any other sort of common request processing. + * It can be a single function or an array of middleware functions. + */ + //httpNodeMiddleware: function(req,res,next) { + // // Handle/reject the request, or pass it on to the http in node by calling next(); + // // Optionally skip our rawBodyParser by setting this to true; + // //req.skipRawBodyParser = true; + // next(); + //}, + + /** When httpAdminRoot is used to move the UI to a different root path, the + * following property can be used to identify a directory of static content + * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot + */ + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + +/******************************************************************************* + * Runtime Settings + * - lang + * - logging + * - contextStorage + * - exportGlobalContextKeys + * - externalModules + ******************************************************************************/ + + /** Uncomment the following to run node-red in your preferred language. + * Available languages include: en-US (default), ja, de, zh-CN, zh-TW, ru, ko + * Some languages are more complete than others. + */ + // lang: "de", + + /** Configure the logging output */ + logging: { + /** Only console logging is currently supported */ + console: { + /** Level of logging to be recorded. Options are: + * fatal - only those errors which make the application unusable should be recorded + * error - record errors which are deemed fatal for a particular request + fatal errors + * warn - record problems which are non fatal + errors + fatal errors + * info - record information about the general running of the application + warn + error + fatal errors + * debug - record information which is more verbose than info + info + warn + error + fatal errors + * trace - record very detailed logging + debug + info + warn + error + fatal errors + * off - turn off all logging (doesn't affect metrics or audit) + */ + level: "info", + /** Whether or not to include metric events in the log output */ + metrics: false, + /** Whether or not to include audit events in the log output */ + audit: false + } + }, + + /** Context Storage + * The following property can be used to enable context storage. The configuration + * provided here will enable file-based context that flushes to disk every 30 seconds. + * Refer to the documentation for further options: https://nodered.org/docs/api/context/ + */ + //contextStorage: { + // default: { + // module:"localfilesystem" + // }, + //}, + + /** `global.keys()` returns a list of all properties set in global context. + * This allows them to be displayed in the Context Sidebar within the editor. + * In some circumstances it is not desirable to expose them to the editor. The + * following property can be used to hide any property set in `functionGlobalContext` + * from being list by `global.keys()`. + * By default, the property is set to false to avoid accidental exposure of + * their values. Setting this to true will cause the keys to be listed. + */ + exportGlobalContextKeys: false, + + /** Configure how the runtime will handle external npm modules. + * This covers: + * - whether the editor will allow new node modules to be installed + * - whether nodes, such as the Function node are allowed to have their + * own dynamically configured dependencies. + * The allow/denyList options can be used to limit what modules the runtime + * will install/load. It can use '*' as a wildcard that matches anything. + */ + externalModules: { + // autoInstall: false, /** Whether the runtime will attempt to automatically install missing modules */ + // autoInstallRetry: 30, /** Interval, in seconds, between reinstall attempts */ + // palette: { /** Configuration for the Palette Manager */ + // allowInstall: true, /** Enable the Palette Manager in the editor */ + // allowUpload: true, /** Allow module tgz files to be uploaded and installed */ + // allowList: [], + // denyList: [] + // }, + // modules: { /** Configuration for node-specified modules */ + // allowInstall: true, + // allowList: [], + // denyList: [] + // } + }, + + +/******************************************************************************* + * Editor Settings + * - disableEditor + * - editorTheme + ******************************************************************************/ + + /** The following property can be used to disable the editor. The admin API + * is not affected by this option. To disable both the editor and the admin + * API, use either the httpRoot or httpAdminRoot properties + */ + //disableEditor: false, + + /** Customising the editor + * See https://nodered.org/docs/user-guide/runtime/configuration#editor-themes + * for all available options. + */ + editorTheme: { + /** The following property can be used to set a custom theme for the editor. + * See https://github.com/node-red-contrib-themes/theme-collection for + * a collection of themes to chose from. + */ + //theme: "", + palette: { + /** The following property can be used to order the categories in the editor + * palette. If a node's category is not in the list, the category will get + * added to the end of the palette. + * If not set, the following default order is used: + */ + //categories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], + }, + projects: { + /** To enable the Projects feature, set this value to true */ + enabled: false, + workflow: { + /** Set the default projects workflow mode. + * - manual - you must manually commit changes + * - auto - changes are automatically committed + * This can be overridden per-user from the 'Git config' + * section of 'User Settings' within the editor + */ + mode: "manual" + } + }, + codeEditor: { + /** Select the text editor component used by the editor. + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired + */ + lib: "monaco", + options: { + /** The follow options only apply if the editor is set to "monaco" + * + * theme - must match the file name of a theme in + * packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/theme + * e.g. "tomorrow-night", "upstream-sunburst", "github", "my-theme" + */ + theme: "vs", + /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html + */ + //fontSize: 14, + //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", + //fontLigatures: true, + } + } + }, + +/******************************************************************************* + * Node Settings + * - fileWorkingDirectory + * - functionGlobalContext + * - functionExternalModules + * - nodeMessageBufferMaxLength + * - ui (for use with Node-RED Dashboard) + * - debugUseColors + * - debugMaxLength + * - execMaxBufferSize + * - httpRequestTimeout + * - mqttReconnectTime + * - serialReconnectTime + * - socketReconnectTime + * - socketTimeout + * - tcpMsgQueueSize + * - inboundWebSocketTimeout + * - tlsConfigDisableLocalFiles + * - webSocketNodeVerifyClient + ******************************************************************************/ + + /** The working directory to handle relative file paths from within the File nodes + * defaults to the working directory of the Node-RED process. + */ + //fileWorkingDirectory: "", + + /** Allow the Function node to load additional npm modules directly */ + functionExternalModules: true, + + /** The following property can be used to set predefined values in Global Context. + * This allows extra node modules to be made available with in Function node. + * For example, the following: + * functionGlobalContext: { os:require('os') } + * will allow the `os` module to be accessed in a Function node using: + * global.get("os") + */ +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, + /** The maximum number of messages nodes will buffer internally as part of their + * operation. This applies across a range of nodes that operate on message sequences. + * defaults to no limit. A value of 0 also means no limit is applied. + */ + //nodeMessageBufferMaxLength: 0, + + /** If you installed the optional node-red-dashboard you can set it's path + * relative to httpNodeRoot + * Other optional properties include + * readOnly:{boolean}, + * middleware:{function or array}, (req,res,next) - http middleware + * ioMiddleware:{function or array}, (socket,next) - socket.io middleware + */ + ui: { path: "" }, + + /** Colourise the console output of the debug node */ + //debugUseColors: true, + + /** The maximum length, in characters, of any message sent to the debug sidebar tab */ + debugMaxLength: 1000, + + /** Maximum buffer size for the exec node. Defaults to 10Mb */ + //execMaxBufferSize: 10000000, + + /** Timeout in milliseconds for HTTP request connections. Defaults to 120s */ + //httpRequestTimeout: 120000, + + /** Retry time in milliseconds for MQTT connections */ + mqttReconnectTime: 15000, + + /** Retry time in milliseconds for Serial port connections */ + serialReconnectTime: 15000, + + /** Retry time in milliseconds for TCP socket connections */ + //socketReconnectTime: 10000, + + /** Timeout in milliseconds for TCP server socket connections. Defaults to no timeout */ + //socketTimeout: 120000, + + /** Maximum number of messages to wait in queue while attempting to connect to TCP socket + * defaults to 1000 + */ + //tcpMsgQueueSize: 2000, + + /** Timeout in milliseconds for inbound WebSocket connections that do not + * match any configured node. Defaults to 5000 + */ + //inboundWebSocketTimeout: 5000, + + /** To disable the option for using local files for storing keys and + * certificates in the TLS configuration node, set this to true. + */ + //tlsConfigDisableLocalFiles: true, + + /** The following property can be used to verify websocket connection attempts. + * This allows, for example, the HTTP request headers to be checked to ensure + * they include valid authentication information. + */ + //webSocketNodeVerifyClient: function(info) { + // /** 'info' has three properties: + // * - origin : the value in the Origin header + // * - req : the HTTP request + // * - secure : true if req.connection.authorized or req.connection.encrypted is set + // * + // * The function should return true if the connection should be accepted, false otherwise. + // * + // * Alternatively, if this function is defined to accept a second argument, callback, + // * it can be used to verify the client asynchronously. + // * The callback takes three arguments: + // * - result : boolean, whether to accept the connection or not + // * - code : if result is false, the HTTP error status to return + // * - reason: if result is false, the HTTP reason string to return + // */ + //}, +} diff --git a/update/2024-1o/update.json b/update/2024-1o/update.json new file mode 100644 index 0000000..9d0651c --- /dev/null +++ b/update/2024-1o/update.json @@ -0,0 +1,124 @@ +{ + "stable": { + "1": { + "src": "stable/OpenScan.py", + "dst": "/usr/lib/python3/dist-packages/OpenScan.py", + "filesize": 10524 + }, + "2": { + "src": "stable/OpenScanStatistics.py", + "dst": "/usr/lib/python3/dist-packages/OpenScanStatistics.py", + "filesize": 1288 + }, + "3": { + "src": "stable/config.txt", + "dst": "/boot/config.txt", + "filesize": 864 + }, + "4": { + "src": "stable/expand_root.sh", + "dst": "/home/pi/OpenScan/files/expand_root.sh", + "filesize": 170 + }, + "5": { + "src": "stable/fla.py", + "dst": "/home/pi/OpenScan/files/fla.py", + "filesize": 17869 + }, + "6": { + "src": "stable/flows.json", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", + "filesize": 355845 + }, + "7": { + "src": "stable/settings.js", + "dst": "/root/.node-red/settings.js", + "filesize": 21248 + } + }, + + "beta": { + "1": { + "src": "beta/OpenScan.py", + "dst": "/usr/lib/python3/dist-packages/OpenScan.py", + "filesize": 10396 + }, + "2": { + "src": "beta/OpenScanSettings.py", + "dst": "/usr/lib/python3/dist-packages/OpenScanSettings.py", + "filesize": 5293 + }, + "3": { + "src": "beta/OpenScanStatistics.py", + "dst": "/usr/lib/python3/dist-packages/OpenScanStatistics.py", + "filesize": 1288 + }, + "4": { + "src": "beta/config.txt", + "dst": "/boot/config.txt", + "filesize": 866 + }, + "5": { + "src": "beta/expand_root.sh", + "dst": "/home/pi/OpenScan/files/expand_root.sh", + "filesize": 170 + }, + "6": { + "src": "beta/fla.py", + "dst": "/home/pi/OpenScan/files/fla.py", + "filesize": 19865 + }, + "7": { + "src": "beta/flows.json", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", + "filesize": 346421 + }, + "8": { + "src": "beta/settings.js", + "dst": "/root/.node-red/settings.js", + "filesize": 21332 + } + }, + "meanwhile": { + "1": { + "src": "meanwhile/OpenScan.py", + "dst": "/usr/lib/python3/dist-packages/OpenScan.py", + "filesize": 10396 + }, + "2": { + "src": "meanwhile/OpenScanSettings.py", + "dst": "/usr/lib/python3/dist-packages/OpenScanSettings.py", + "filesize": 5520 + }, + "3": { + "src": "meanwhile/OpenScanStatistics.py", + "dst": "/usr/lib/python3/dist-packages/OpenScanStatistics.py", + "filesize": 2682 + }, + "4": { + "src": "meanwhile/config.txt", + "dst": "/boot/config.txt", + "filesize": 867 + }, + "5": { + "src": "meanwhile/expand_root.sh", + "dst": "/home/pi/OpenScan/files/expand_root.sh", + "filesize": 170 + }, + "6": { + "src": "meanwhile/fla.py", + "dst": "/home/pi/OpenScan/files/fla.py", + "filesize": 19750 + }, + "7": { + "src": "meanwhile/flows.json", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", + "filesize": 353170 + }, + "8": { + "src": "meanwhile/settings.js", + "dst": "/root/.node-red/settings.js", + "filesize": 21386 + } + } +} \ No newline at end of file diff --git a/update/beta/Arducam.py b/update/beta/Arducam.py deleted file mode 100644 index 941e07b..0000000 --- a/update/beta/Arducam.py +++ /dev/null @@ -1,202 +0,0 @@ -import time -import os - -try: - import v4l2 -except Exception as e: - print(e) - print("Try to install v4l2-fix") - try: - from pip import main as pipmain - except ImportError: - from pip._internal import main as pipmain - pipmain(['install', 'v4l2-fix']) - print("\nTry to run the focus program again.") - exit(0) - -import fcntl -import errno - -# # Type -# v4l2.V4L2_CTRL_TYPE_INTEGER -# v4l2.V4L2_CTRL_TYPE_BOOLEAN -# v4l2.V4L2_CTRL_TYPE_MENU -# v4l2.V4L2_CTRL_TYPE_BUTTON -# v4l2.V4L2_CTRL_TYPE_INTEGER64 -# v4l2.V4L2_CTRL_TYPE_CTRL_CLASS -# # Flags -# v4l2.V4L2_CTRL_FLAG_DISABLED -# v4l2.V4L2_CTRL_FLAG_GRABBED -# v4l2.V4L2_CTRL_FLAG_READ_ONLY -# v4l2.V4L2_CTRL_FLAG_UPDATE -# v4l2.V4L2_CTRL_FLAG_INACTIVE -# v4l2.V4L2_CTRL_FLAG_SLIDER - -def assert_valid_queryctrl(queryctrl): - return queryctrl.type & ( - v4l2.V4L2_CTRL_TYPE_INTEGER - | v4l2.V4L2_CTRL_TYPE_BOOLEAN - | v4l2.V4L2_CTRL_TYPE_MENU - | v4l2.V4L2_CTRL_TYPE_BUTTON - | v4l2.V4L2_CTRL_TYPE_INTEGER64 - | v4l2.V4L2_CTRL_TYPE_CTRL_CLASS - | 7 - | 8 - | 9 - ) and queryctrl.flags & ( - v4l2.V4L2_CTRL_FLAG_DISABLED - | v4l2.V4L2_CTRL_FLAG_GRABBED - | v4l2.V4L2_CTRL_FLAG_READ_ONLY - | v4l2.V4L2_CTRL_FLAG_UPDATE - | v4l2.V4L2_CTRL_FLAG_INACTIVE - | v4l2.V4L2_CTRL_FLAG_SLIDER - ) - -def get_device_controls_menu(fd, queryctrl): - querymenu = v4l2.v4l2_querymenu(queryctrl.id, queryctrl.minimum) - while querymenu.index <= queryctrl.maximum: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYMENU, querymenu) - yield querymenu - querymenu.index += 1 - -def get_device_controls_by_class(fd, control_class): - # enumeration by control class - queryctrl = v4l2.v4l2_queryctrl(control_class | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - while True: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - except IOError as e: - assert e.errno == errno.EINVAL - break - if v4l2.V4L2_CTRL_ID2CLASS(queryctrl.id) != control_class: - break - yield queryctrl - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - -def getdict(struct): - val = dict((field, getattr(struct, field)) for field, _ in struct._fields_) - val.pop("reserved") - return val - -def get_device_controls(fd): - # original enumeration method - queryctrl = v4l2.v4l2_queryctrl(v4l2.V4L2_CID_BASE) - while queryctrl.id < v4l2.V4L2_CID_LASTP1: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - print(queryctrl.name) - except IOError as e: - # this predefined control is not supported by this device - assert e.errno == errno.EINVAL - queryctrl.id += 1 - continue - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id + 1) - -def get_ctrls(vd): - ctrls = [] - # enumeration by control class - for class_ in (v4l2.V4L2_CTRL_CLASS_USER, v4l2.V4L2_CTRL_CLASS_MPEG, v4l2.V4L2_CTRL_CLASS_CAMERA): - for queryctrl in get_device_controls_by_class(vd, class_): - ctrl = getdict(queryctrl) - if queryctrl.type == v4l2.V4L2_CTRL_TYPE_MENU: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - # print(querymenu.name) - ctrl["menu"].append(querymenu.name) - - if queryctrl.type == 9: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - ctrl["menu"].append(querymenu.index) - ctrls.append(ctrl) - return ctrls - -def set_ctrl(vd, id, value): - ctrl = v4l2.v4l2_control() - ctrl.id = id - ctrl.value = value - try: - fcntl.ioctl(vd, v4l2.VIDIOC_S_CTRL, ctrl) - except IOError as e: - print(e) - -def get_ctrl(vd, id): - ctrl = v4l2.v4l2_control() - ctrl.id = id - try: - fcntl.ioctl(vd, v4l2.VIDIOC_G_CTRL, ctrl) - except IOError as e: - print(e) - return None - return ctrl.value - - -class Focuser: - FOCUS_ID = 0x009a090a - dev = None - - def __init__(self, dev=0): - self.focus_value = 0 - self.dev = dev - - if type(dev) == int or (type(dev) == str and dev.isnumeric()): - self.dev = "/dev/video{}".format(dev) - - self.fd = open(self.dev, 'r') - self.ctrls = get_ctrls(self.fd) - self.hasFocus = False - for ctrl in self.ctrls: - if ctrl['id'] == Focuser.FOCUS_ID: - self.hasFocus = True - self.opts[Focuser.OPT_FOCUS]["MIN_VALUE"] = ctrl['minimum'] - self.opts[Focuser.OPT_FOCUS]["MAX_VALUE"] = ctrl['maximum'] - self.opts[Focuser.OPT_FOCUS]["DEF_VALUE"] = ctrl['default'] - self.focus_value = get_ctrl(self.fd, Focuser.FOCUS_ID) - - if not self.hasFocus: - raise RuntimeError("Device {} has no focus_absolute control.".format(self.dev)) - - def read(self): - return self.focus_value - - def write(self, value): - self.focus_value = value - # os.system("v4l2-ctl -d {} -c focus_absolute={}".format(self.dev, value)) - set_ctrl(self.fd, Focuser.FOCUS_ID, value) - - OPT_BASE = 0x1000 - OPT_FOCUS = OPT_BASE | 0x01 - OPT_ZOOM = OPT_BASE | 0x02 - OPT_MOTOR_X = OPT_BASE | 0x03 - OPT_MOTOR_Y = OPT_BASE | 0x04 - OPT_IRCUT = OPT_BASE | 0x05 - opts = { - OPT_FOCUS : { - "MIN_VALUE": 0, - "MAX_VALUE": 1000, - "DEF_VALUE": 0, - }, - } - def reset(self,opt,flag = 1): - info = self.opts[opt] - if info == None or info["DEF_VALUE"] == None: - return - self.set(opt,info["DEF_VALUE"]) - - def get(self,opt,flag = 0): - info = self.opts[opt] - return self.read() - - def set(self,opt,value,flag = 1): - info = self.opts[opt] - if value > info["MAX_VALUE"]: - value = info["MAX_VALUE"] - elif value < info["MIN_VALUE"]: - value = info["MIN_VALUE"] - self.write(value) - print("write: {}".format(value)) - - def __del__(self): - self.fd.close() - -pass diff --git a/update/beta/OpenScan.py b/update/beta/OpenScan.py index 0ebce0d..681c78d 100644 --- a/update/beta/OpenScan.py +++ b/update/beta/OpenScan.py @@ -1,5 +1,6 @@ basepath = '/home/pi/OpenScan/' from os.path import isfile +import os def load_bool(name): filename = basepath+'settings/'+name @@ -13,6 +14,74 @@ def load_bool(name): value = False return value +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + + return True + + def load_str(name): filename = basepath+'settings/'+name if not isfile(filename): @@ -70,7 +139,6 @@ def motorrun(motor,angle,ES_enable=False,ES_start_state = True): from time import sleep from math import cos msg = {'cmd':'set'} - camera('/ping', msg) GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) @@ -97,7 +165,14 @@ def motorrun(motor,angle,ES_enable=False,ES_start_state = True): step_count=-step_count for x in range(step_count): if ES_enable == True and GPIO.input(ES_pin) != ES_start_state: - break + i = 0 + while i <= 10: + if GPIO.input(ES_pin) == ES_start_state: + i = 11 + if i == 10: + return + i = i + 1 + GPIO.output(steppin, GPIO.HIGH) if x<=ramp and x<=step_count/2: delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) @@ -114,7 +189,6 @@ def motorrun(motor,angle,ES_enable=False,ES_start_state = True): def ringlight(number,state): import RPi.GPIO as GPIO msg = {'cmd':'set'} - camera('/ping', msg) pin = load_int('pin_ringlight' + str(number)) GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) @@ -201,3 +275,42 @@ def create_coordinates(angle_min, angle_max,point_count): point_count=point_count+1 return filtered + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/beta/config.txt b/update/beta/config.txt old mode 100644 new mode 100755 index ce06bd8..cc525ae --- a/update/beta/config.txt +++ b/update/beta/config.txt @@ -2,10 +2,8 @@ # http://rpf.io/configtxt # Some settings may impact device functionality. See link above for details - # uncomment if you get no picture on HDMI for a default "safe" mode #hdmi_safe=1 -hdmi_blanking=2 # uncomment the following to adjust overscan. Use positive numbers if console # goes off screen, and negative if there is too much border @@ -55,13 +53,13 @@ hdmi_blanking=2 dtparam=audio=on # Automatically load overlays for detected cameras -camera_auto_detect=0 +camera_auto_detect=1 # Automatically load overlays for detected DSI displays display_auto_detect=1 # Enable DRM VC4 V3D driver -#dtoverlay=vc4-kms-v3d +dtoverlay=vc4-kms-v3d max_framebuffers=2 # Disable compensation for displays with overscan @@ -73,13 +71,15 @@ disable_overscan=1 # (e.g. for USB device mode) or if USB support is not required. otg_mode=1 +[all] + [pi4] # Run as fast as firmware / board allows arm_boost=1 [all] - camera_auto_detect=0 gpu_mem=256 dtoverlay=vc4-fkms-v3d -dtoverlay=imx519,media-controller=1 +dtoverlay=imx519 +#dtoverlay=imx519,media-controller=1 diff --git a/update/beta/fla.py b/update/beta/fla.py index 5fe4649..57f4660 100644 --- a/update/beta/fla.py +++ b/update/beta/fla.py @@ -1,12 +1,17 @@ -from flask import Flask, make_response, jsonify, request, abort -from PIL import Image -import gphoto2 as gp +from flask import Flask, make_response, jsonify, request, abort, redirect +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont from time import sleep, time import shutil from OpenScan import load_int, load_float, load_bool, ringlight import RPi.GPIO as GPIO from math import sqrt -import os +import os +import math +from skimage import io, feature, color, transform +import numpy as np +from scipy import ndimage +import socket GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) @@ -15,134 +20,331 @@ basedir = '/home/pi/OpenScan/' timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + ################################################################################################################### @app.route('/shutdown', methods=['get']) def shutdown(): - delay = 0.1 - ringlight(2,False) - - for i in range (5): - ringlight(1,True) - sleep(delay) - ringlight(1,False) - sleep(delay) - os.system('shutdown -h now') + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + f = open("/home/pi/OpenScan/settings/session_token", "r") + session_token = (f.readline())[:20] + if shutdown_token == session_token: + + delay = 0.1 + ringlight(2,False) + + for i in range (5): + ringlight(1,True) + sleep(delay) + ringlight(1,False) + sleep(delay) + os.system('shutdown -h now') + + else: + return redirect("http://" + hostname, code=302) ################################################################################################################### @app.route('/reboot', methods=['get']) def reboot(): - delay = 0.1 - ringlight(2,False) + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + f = open("/home/pi/OpenScan/settings/session_token", "r") + session_token = (f.readline())[:20] + if shutdown_token == session_token: + delay = 0.1 + ringlight(2,False) + + for i in range (5): + ringlight(1,True) + sleep(delay) + ringlight(1,False) + sleep(delay) + + os.system('reboot -h') + else: + return redirect("http://" + hostname, code=302) +################################################################################################################### + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) - for i in range (5): - ringlight(1,True) - sleep(delay) - ringlight(1,False) - sleep(delay) + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') - os.system('reboot -h') + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wrong aspect ratio! +# preview_config = picam2.create_preview_configuration(main={"size": (2028, 1520)}) + preview_config = picam2.create_preview_configuration(main={"size": (2028, 1520)}, controls ={"FrameDurationLimits": (1, 1000000)}) + +# preview_config = picam2.create_preview_configuration(main={"size": (2328, 1748)}) + capture_config = picam2.create_still_configuration(controls ={"FrameDurationLimits": (1, 1000000)}) + picam2.configure(preview_config) + picam2.controls.AnalogueGain = 1.0 + picam2.start() + return ({}, 200) + +################################################################################################################### +@app.route('/picam2_take_photo', methods=['get']) +def picam2_take_photo(): + starttime = time() + + cropx = load_int('cam_cropx')/200 + cropy = load_int('cam_cropy')/200 + rotation = load_int('cam_rotation') + img = picam2.capture_image() + + if cam_mode !=1: + img = img.convert('RGB') + w,h = img.size + + if cropx != 0 or cropy != 0: + img = img.crop((w*cropx, h*cropy, w * (1-cropx), h * (1-cropy))) + + if rotation == 90: + img = img.transpose(Image.ROTATE_90) + elif rotation == 180: + img= img.transpose(Image.ROTATE_180) + elif rotation == 270: + img= img.transpose(Image.ROTATE_270) + + if load_bool("cam_mask"): + if cam_mode == 1: + downscale = 0.045*1.4 + else: + downscale = 0.1*1.4 + img = create_mask(img, downscale) + + if load_bool("cam_features") and not load_bool("cam_sharparea"): + img = plot_orb_keypoints(img) + + if load_bool("cam_sharparea") and not load_bool("cam_features"): + img2 = highlight_sharpest_areas(img) + img = overlay_mask(img, img2) + + if cam_mode != 1 and not load_bool("cam_sharparea") and not load_bool("cam_features"): + img = add_histo(img) + + img.save("/home/pi/OpenScan/tmp2/preview.jpg", quality=load_int('cam_jpeg_quality')) + print("total " + str(int(1000*(time()-starttime))) + "ms") + starttime = time() + + return ({}, 200) ################################################################################################################### -@app.route('/ping', methods=['get']) -def ping(): - global timer - cmd = str(request.args.get('cmd')) - if cmd == 'set': - timer = time() - inactive = time() - timer - return ({'inactive':inactive}, 200) +@app.route('/picam2_focus', methods=['get']) +def picam2_focus(): + focus = float(request.args.get('focus')) + picam2.set_controls({"AfMode": 0, "LensPosition": focus}) + return ({}, 200) ################################################################################################################### -@app.route('/gphoto_init', methods=['get']) -def gphoto_init(): - global camera - camera = gp.Camera() - camera.init() +@app.route('/picam2_af1', methods=['get']) +def picam2_af1(): + from libcamera import controls + + picam2.set_controls({"AfMode": 2 ,"AfTrigger": 0, "AfRange":controls.AfRangeEnum.Macro}) return ({}, 200) ################################################################################################################### -@app.route('/gphoto_preview', methods=['get']) -def gphoto_preview(): - filepath = str(request.args.get('filepath')) - camera_file = gp.gp_camera_capture_preview(camera)[1] - target = basedir + filepath - camera_file.save(target) +@app.route('/picam2_af2', methods=['get']) +def picam2_af2(): + picam2.set_controls({"AfMode": 2 ,"AfTrigger": 0}) return ({}, 200) + ################################################################################################################### -@app.route('/gphoto_capture', methods=['get']) -def gphoto_capture(): - filepath = str(request.args.get('filepath')) - file_path = camera.capture(gp.GP_CAPTURE_IMAGE) - camera_file = camera.file_get(file_path.folder, file_path.name, gp.GP_FILE_TYPE_NORMAL) - camera_file.save(basedir + filepath) +@app.route('/picam2_exposure', methods=['get']) +def picam2_exposure(): + exposure = int(request.args.get('exposure')) + picam2.controls.AnalogueGain = 1.0 + picam2.controls.ExposureTime = exposure return ({}, 200) ################################################################################################################### -@app.route('/gphoto_test', methods=['get']) -def gphoto_test(): - text = camera.get_summary() +@app.route('/picam2_contrast', methods=['get']) +def picam2_contrast(): + contrast = float(request.args.get('contrast')) + picam2.controls.Contrast = contrast return ({}, 200) ################################################################################################################### -@app.route('/gphoto_exit', methods=['get']) -def gphoto_exit(): - global camera - camera.exit() +@app.route('/picam2_saturation', methods=['get']) +def picam2_saturation(): + saturation = float(request.args.get('saturation')) + picam2.controls.Saturation = saturation return ({}, 200) ################################################################################################################### -@app.route('/crop', methods=['get']) -def crop(): - output_downscale = load_bool('cam_output_downscale') - output_resolution = load_int('cam_output_resolution') - preview_resolution = load_int('cam_preview_resolution') - filepath_in = basedir + str(request.args.get('filepath_in')) - filepath_out = basedir + str(request.args.get('filepath_out')) - cropx = int(request.args.get('cropx'))/200 - cropy = int(request.args.get('cropy'))/200 - rotation = int(request.args.get('rotation')) - preview = str(request.args.get('preview')) - downscale = 1 - - with Image.open(filepath_in) as img: - w,h = img.size - if cropx != 0 or cropy != 0: - img = img.crop((w*cropx, h*cropy, w * (1-cropx), h * (1-cropy))) - if rotation == 90: - img = img.transpose(Image.ROTATE_90) - elif rotation == 180: - img= img.transpose(Image.ROTATE_180) - elif rotation == 270: - img= img.transpose(Image.ROTATE_270) - - if preview == "True": - w,h = img.size - factor = (w*h)/preview_resolution - if factor > 1: - img = img.resize((int(w/sqrt(factor)),int(h/sqrt(factor))),Image.ANTIALIAS) - - elif output_downscale == True: - w,h = img.size - factor = (w*h)/output_resolution - if factor > 1: - img = img.resize((int(w/sqrt(factor)),int(h/sqrt(factor))),Image.ANTIALIAS) - - img.save(filepath_out, quality=95, subsampling=0) - +@app.route('/picam2_switch_mode', methods=['get']) +def picam2_switch_mode(): + global cam_mode + cam_mode = int(request.args.get('mode')) + if cam_mode == 1: + picam2.switch_mode(capture_config) + else: + picam2.switch_mode(preview_config) return ({}, 200) - ################################################################################################################### -@app.route('/external_capture', methods=['get']) -def external_capture(): - pin = load_int('pin_external') - delay_before = load_float('cam_delay_before') - timeout = load_float('cam_timeout')/1000 - delay_after = load_float('cam_delay_after') - GPIO.setup(pin, GPIO.OUT) - GPIO.output(pin, GPIO.LOW) - sleep(delay_before) - GPIO.output(pin, GPIO.HIGH) - sleep(timeout) - GPIO.output(pin, GPIO.LOW) - sleep(delay_after) +@app.route('/picam2_show_mode', methods=['get']) +def picam2_show_mode(): + global cam_mode + return({"mode":cam_mode},200) +################################################################################################################### +@app.route('/picam2_af', methods=['get']) +def picam2_af(): + picam2.set_controls({"AfMode": 1 ,"AfTrigger": 0}) # --> wait 3-5s return ({}, 200) - - +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') if __name__ == '__main__': # app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) diff --git a/update/main/flows.json b/update/beta/flows.json.tmpl similarity index 58% rename from update/main/flows.json rename to update/beta/flows.json.tmpl index b79939e..20fb35f 100644 --- a/update/main/flows.json +++ b/update/beta/flows.json.tmpl @@ -1,55 +1,66 @@ [ { - "id": "829d803b6033a693", + "id": "e6f4d02efb300ea9", "type": "tab", - "label": "HOME", + "label": "Init", "disabled": false, "info": "", "env": [] }, { - "id": "1613373abaf77a2c", + "id": "481edaf6db5a7a54", "type": "tab", - "label": "SCAN", + "label": "Scan", "disabled": false, "info": "", "env": [] }, { - "id": "4981d84ef1a366d1", + "id": "80a3942785a26c29", "type": "tab", - "label": "Files&Cloud", + "label": "Files", "disabled": false, "info": "", "env": [] }, { - "id": "017bd4e4a428bee5", + "id": "e43a27722b508115", "type": "tab", - "label": "SETTINGS", + "label": "Settings", "disabled": false, "info": "", "env": [] }, { - "id": "c8e7ecb5849edb9a", + "id": "a5557543ccff5889", "type": "tab", - "label": "UPDATE", + "label": "Update", "disabled": false, "info": "", "env": [] }, { - "id": "b3150b13e34b1fe8", + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", "type": "ui_tab", - "name": "OpenScan", + "name": "Scan", "icon": "dashboard", - "order": 1, + "order": 2, "disabled": false, "hidden": false }, { - "id": "b6e9c2df6b28ff66", + "id": "5c06cb6bcc371ee6", "type": "ui_base", "theme": { "name": "theme-dark", @@ -61,8 +72,8 @@ "reset": false }, "darkTheme": { - "default": "#097479", - "baseColor": "#097479", + "default": "{{ darktheme-default }}", + "baseColor": "{{ darktheme-basecolor }}", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": true, "reset": false @@ -71,16 +82,17 @@ "name": "Untitled Theme 1", "default": "#4B7930", "baseColor": "#4B7930", - "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false }, "themeState": { "base-color": { - "default": "#097479", - "value": "#097479", + "default": "{{ base-color-default }}", + "value": "{{ base-color-value }}", "edited": false }, "page-titlebar-backgroundColor": { - "value": "#097479", + "value": "{{ page-titlebar-bgcolor }}", "edited": false }, "page-backgroundColor": { @@ -108,7 +120,7 @@ "edited": false }, "widget-backgroundColor": { - "value": "#097479", + "value": "{{ widget-bgcolor }}", "edited": false }, "widget-borderColor": { @@ -128,190 +140,123 @@ } }, "site": { - "name": "OpenScan 3D Scanner", + "name": "OpenScan", "hideToolbar": "false", "allowSwipe": "false", "lockMenu": "false", "allowTempTheme": "true", "dateFormat": "DD/MM/YYYY", "sizes": { - "sx": 46, - "sy": 46, - "gx": 10, - "gy": 10, + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, "cx": 6, "cy": 6, - "px": 6, - "py": 6 + "px": 0, + "py": 0 } } }, { - "id": "729f9ea6e3513c9b", - "type": "ui_group", - "name": "Home", - "tab": "b3150b13e34b1fe8", - "order": 2, - "disp": false, - "width": "6", - "collapse": false, - "className": "" + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 6 }, { - "id": "65ae49b64fa0d83e", - "type": "ui_tab", - "name": "Settings", - "icon": "dashboard", - "order": 4, - "disabled": false, - "hidden": false + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 5 }, { - "id": "4fe6b4c0ade0938a", + "id": "b5fdd57b.15eda8", "type": "ui_group", - "name": "General", - "tab": "65ae49b64fa0d83e", + "name": "Main", + "tab": "15a222ed.d70a7d", "order": 1, - "disp": true, - "width": "6", - "collapse": true, - "className": "" + "disp": false, + "width": 13, + "collapse": false }, { - "id": "0fe66c9190b8a87c", + "id": "db43d646.2074c8", "type": "ui_group", - "name": "Network", - "tab": "65ae49b64fa0d83e", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", "order": 2, "disp": true, "width": "6", - "collapse": true, - "className": "" - }, - { - "id": "93aadb71dee6d977", - "type": "ui_group", - "name": "Camera", - "tab": "65ae49b64fa0d83e", - "order": 4, - "disp": true, - "width": "6", - "collapse": true, - "className": "" - }, - { - "id": "d49a6dfd7fb17096", - "type": "ui_group", - "name": "Motor", - "tab": "65ae49b64fa0d83e", - "order": 5, - "disp": true, - "width": "6", - "collapse": true, - "className": "" - }, - { - "id": "644b3bcc903d46ca", - "type": "ui_group", - "name": "Pinout", - "tab": "65ae49b64fa0d83e", - "order": 6, - "disp": true, - "width": "6", - "collapse": true, - "className": "" + "collapse": false }, { - "id": "e23b837a9f040895", + "id": "15a222ed.d70a7d", "type": "ui_tab", - "name": "Scan", + "name": "Files&Cloud", "icon": "dashboard", - "order": 2, + "order": 3, "disabled": false, "hidden": false }, { - "id": "7aaf184330605300", + "id": "365a30d0dfa83e95", "type": "ui_group", - "name": "Settings", + "name": "settings", "tab": "e23b837a9f040895", "order": 1, "disp": false, - "width": "6", - "collapse": false, - "className": "" - }, - { - "id": "ce9cc9d915dc6eb6", - "type": "ui_group", - "name": "Picamera", - "tab": "e23b837a9f040895", - "order": 2, - "disp": false, - "width": "12", + "width": 7, "collapse": false, "className": "" }, { - "id": "90223f7ddc082321", + "id": "ac7409105cfecac6", "type": "ui_group", - "name": "Arducam", + "name": "advanced", "tab": "e23b837a9f040895", "order": 3, "disp": false, - "width": 12, + "width": 7, "collapse": false, "className": "" }, { - "id": "7625f9c9e8dbc5c6", - "type": "ui_spacer", - "z": "017bd4e4a428bee5", - "name": "spacer", - "group": "", - "order": 4, - "width": 1, - "height": 1 - }, - { - "id": "3b4bd36726be16d5", + "id": "729f9ea6e3513c9b", "type": "ui_group", - "name": "OpenScanCloud", - "tab": "65ae49b64fa0d83e", - "order": 3, - "disp": true, + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, "width": "6", "collapse": false, "className": "" }, { - "id": "b5fdd57b.15eda8", + "id": "5b3e5aca21140e9a", "type": "ui_group", - "name": "Main", - "tab": "15a222ed.d70a7d", + "name": "Update", + "tab": "b3150b13e34b1fe8", "order": 1, "disp": false, - "width": 13, - "collapse": false - }, - { - "id": "db43d646.2074c8", - "type": "ui_group", - "name": "OpenScanCloud", - "tab": "15a222ed.d70a7d", - "order": 2, - "disp": true, "width": "6", - "collapse": false + "collapse": false, + "className": "" }, { - "id": "15a222ed.d70a7d", + "id": "b3150b13e34b1fe8", "type": "ui_tab", - "name": "Files&Cloud", + "name": "OpenScan", "icon": "dashboard", - "order": 3, + "order": 1, "disabled": false, - "hidden": false + "hidden": true }, { "id": "ddbd496e.93a288", @@ -339,285 +284,284 @@ "type": "ui_tab", "name": "Update & Info", "icon": "dashboard", - "order": 5, + "order": 4, "disabled": false, "hidden": false }, { - "id": "1f7f7e1e24f5ad9b", + "id": "4390b2ebcbbe104c", "type": "ui_group", - "name": "Initialize", - "tab": "b3150b13e34b1fe8", - "order": 3, - "disp": false, + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, "width": "6", - "collapse": false, + "collapse": true, "className": "" }, { - "id": "5b3e5aca21140e9a", + "id": "8ab79a98e536e0d6", "type": "ui_group", - "name": "Update", - "tab": "b3150b13e34b1fe8", - "order": 1, - "disp": false, + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Motor", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, "width": "6", "collapse": false, "className": "" }, { - "id": "700f47327133ab68", + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", "type": "ui_spacer", - "z": "829d803b6033a693", + "z": "e43a27722b508115", "name": "spacer", - "group": "729f9ea6e3513c9b", - "order": 6, + "group": "db43d646.2074c8", + "order": 1, "width": 1, "height": 1 }, { - "id": "ebf828f29201a53b", + "id": "33b6d7317d1524b8", "type": "ui_spacer", - "z": "829d803b6033a693", + "z": "e43a27722b508115", "name": "spacer", - "group": "729f9ea6e3513c9b", - "order": 8, + "group": "db43d646.2074c8", + "order": 3, "width": 1, "height": 1 }, { - "id": "3b4961c4e72ff58a", + "id": "aaf5b874c52a58aa", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "4fe6b4c0ade0938a", - "order": 6, - "width": 6, + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, "height": 1 }, { - "id": "5ef40dca2c6c6aab", + "id": "f8d8740dcbf499fb", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "4fe6b4c0ade0938a", + "group": "365a30d0dfa83e95", "order": 11, - "width": 6, + "width": 1, "height": 1 }, { - "id": "bdd26746cc1e1ba0", + "id": "7ac0cb556740d159", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "3b4bd36726be16d5", - "order": 6, - "width": 2, + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, "height": 1 }, { - "id": "3584b5ef2b7acb72", + "id": "4de2414e29020c74", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "3b4bd36726be16d5", - "order": 8, - "width": 2, + "group": "90223f7ddc082321", + "order": 2, + "width": 7, "height": 1 }, { - "id": "cac67f0e.f01fa", - "type": "ui_group", - "name": "Button Top", - "tab": "", - "order": 1, - "disp": true, - "width": "6", - "collapse": false + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 }, { - "id": "b73c392ffd8ca3f2", + "id": "ce21673092264c38", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "90223f7ddc082321", - "order": 14, - "width": 2, + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, "height": 1 }, { - "id": "89fe04171cd2f35b", + "id": "3f7b77f8a1675d27", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "90223f7ddc082321", - "order": 15, - "width": 2, + "group": "12b719cba49817c9", + "order": 7, + "width": 4, "height": 1 }, { - "id": "80c9c0059de08f02", + "id": "0799b02d12fc3a14", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "90223f7ddc082321", - "order": 16, - "width": 2, + "group": "7a3279eea439bcdd", + "order": 25, + "width": 6, "height": 1 }, { - "id": "3fe52603e2ac73b6", - "type": "ui_template", - "z": "829d803b6033a693", - "group": "729f9ea6e3513c9b", - "name": "Background", - "order": 1, - "width": 0, - "height": 0, - "format": "", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": false, - "templateScope": "global", - "className": "", - "x": 110, - "y": 40, - "wires": [ - [] - ] + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": false, + "className": "" }, - { - "id": "4468f691.103eb8", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 2, - "width": 3, - "height": 2, - "passthru": false, - "label": "SCAN", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "1", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 100, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] +{ + "id": "15edc2ce885dddb3", + "type": "ui_group", + "name": "Colorines", + "tab": "457102eadc9ddb6c", + "order": 8, + "disp": true, + "width": "6", + "collapse": false, + "className": "" + }, +{ + "id": "33aff36289823faa", + "type": "ui_group", + "name": "Monitoring", + "tab": "457102eadc9ddb6c", + "order": 9, + "disp": true, + "width": "6", + "collapse": false, + "className": "" }, { - "id": "6560dd25.9e76c4", - "type": "ui_button", - "z": "829d803b6033a693", + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", "name": "", - "group": "729f9ea6e3513c9b", - "order": 4, - "width": 3, - "height": 2, - "passthru": false, - "label": "Settings", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "3", - "payloadType": "num", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, "topic": "", - "topicType": "str", + "payload": "", + "payloadType": "date", "x": 100, - "y": 180, + "y": 460, "wires": [ [ - "62cd5288.2805fc" + "949bafced17d66d6" ] ] }, { - "id": "62cd5288.2805fc", - "type": "ui_ui_control", - "z": "829d803b6033a693", - "name": "", - "events": "all", - "x": 280, - "y": 100, + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 460, "wires": [ [] ] }, { - "id": "71e72293.91c6fc", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 3, - "width": 3, - "height": 2, - "passthru": false, - "label": "Files", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "2", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 140, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] - }, - { - "id": "e7306ef2.3b4df", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 5, - "width": 3, - "height": 2, - "passthru": false, - "label": "Update&Info", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "4", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 110, - "y": 220, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] - }, - { - "id": "88edad7ca53698fd", + "id": "a1f0ed7d5a9d670e", "type": "inject", - "z": "829d803b6033a693", - "name": "1s", + "z": "e6f4d02efb300ea9", + "name": "", "props": [ { - "p": "payload" + "p": "overwrite", + "v": "false", + "vt": "bool" }, { "p": "topic", @@ -627,112 +571,60 @@ "repeat": "", "crontab": "", "once": true, - "onceDelay": "1", + "onceDelay": "0.1", "topic": "", - "payload": "true", - "payloadType": "bool", - "x": 90, - "y": 400, + "x": 110, + "y": 60, "wires": [ [ - "000a811a215e08d4", - "83c2b5ea51f0fec3", - "88fde4ab78c965d7", - "bee62d2a99cbc63b", - "8e39e4a037487ecd", - "bb84b9e5c7d8e21f", - "7113d7b25a851151", - "c4c1580c289fc7bd" + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6" ] ] }, { - "id": "bd75f33b8a57c522", - "type": "link out", - "z": "829d803b6033a693", - "name": "enable", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "92c98e6ce7cd25f9", - "b33d604c.5f1a6" - ], - "x": 335, - "y": 440, - "wires": [] - }, - { - "id": "000a811a215e08d4", + "id": "544d20f02215011a", "type": "function", - "z": "829d803b6033a693", - "name": "enable", - "func": "msg.enabled = true\nmsg.payload = 1\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 230, - "y": 440, + "x": 330, + "y": 60, "wires": [ [ - "bd75f33b8a57c522" + "c77552216a8bb781" ] ] }, { - "id": "83c2b5ea51f0fec3", - "type": "function", - "z": "829d803b6033a693", - "name": "disable", - "func": "msg.enabled = false\nreturn msg", + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 240, - "y": 480, + "x": 540, + "y": 60, "wires": [ [ - "6b94bf2295b1b31d" + "960912e90ba5b5bc" ] ] }, - { - "id": "6b94bf2295b1b31d", - "type": "link out", - "z": "829d803b6033a693", - "name": "disable", - "mode": "link", - "links": [ - "a1d29e56599da0bd" - ], - "x": 335, - "y": 480, - "wires": [] - }, - { - "id": "88fde4ab78c965d7", - "type": "function", - "z": "829d803b6033a693", - "name": "write", - "func": "var file = 'status_cloud'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\ncontent = 'ready'\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 230, - "y": 520, - "wires": [ - [] - ] - }, { "id": "960912e90ba5b5bc", "type": "link out", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "started1s", "mode": "link", "links": [ @@ -752,16 +644,43 @@ "e5f38b4a07a5e278", "f0b355967b33dfee", "d0104e0163745993", - "5e7d5e4335d37794" + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244" ], - "x": 615, - "y": 800, + "x": 645, + "y": 60, "wires": [] }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, { "id": "168d72a54504b327", "type": "inject", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "5/0.1s", "props": [ { @@ -780,7 +699,7 @@ "payload": "", "payloadType": "str", "x": 100, - "y": 720, + "y": 380, "wires": [ [ "6c6ef2255a7d39e5" @@ -790,64 +709,106 @@ { "id": "6c6ef2255a7d39e5", "type": "link out", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "repeat 5s/0.1s", "mode": "link", "links": [ "61990987acd0f263", - "2415272f42ce468c" + "2415272f42ce468c", + "6bf8344af427a6ba" ], - "x": 195, - "y": 720, + "x": 205, + "y": 380, "wires": [] }, { - "id": "bee62d2a99cbc63b", - "type": "function", - "z": "829d803b6033a693", - "name": "global", - "func": "global.set('flag_pw', true)\nglobal.set('flag', true)\nglobal.set('combine', false)\nglobal.set('focus', 2838)\nglobal.set('focus1', 0)\nglobal.set('focus2', 0)\n\nglobal.set('focuser', true)\n", + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 230, - "y": 400, + "x": 270, + "y": 140, "wires": [ [ - "f20da2fc4978b7bf" + "eb1a2387a1eeea76" ] ] }, { - "id": "544d20f02215011a", + "id": "b1e2491c952f84c9", "type": "function", - "z": "829d803b6033a693", - "name": "CREATE FACTORY DEFAULT", - "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cameras':{\n 'imx519':[4656,3496],\n 'imx219':[3280,2464],\n 'imx477':[4056,3040],\n 'ov5647':[2592,1944],\n 'imx378':[3840,2880],\n 'ov9271':[1280,800],\n 'imx290a':[1920,1080],\n 'imx290b':[1920,1080],\n },\n 'cam_AFmode':true,\n 'cam_STmode':true,\n 'cam_stacksize':2,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':0,\n 'cam_saturation':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'hostname':'',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n 'pin_endstop1':24,\n 'pin_endstop2':25,\n 'pin_external':10,\n 'pin_ringlight1':17,\n 'pin_ringlight2':27,\n 'pin_rotor_dir':5,\n 'pin_rotor_enable':23,\n 'pin_rotor_step':6,\n 'pin_tt_dir':9,\n 'pin_tt_enable':22,\n 'pin_tt_step':11,\n 'rotor_acc':1,\n 'rotor_accramp':2000,\n 'rotor_angle':10,\n 'rotor_anglemax':60,\n 'rotor_anglemin':-20,\n 'rotor_anglestart':0,\n 'rotor_delay':0.0001,\n 'rotor_dir':1,\n 'rotor_stepsperrotation':48000,\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n 'tt_acc':1,\n 'tt_accramp':200,\n 'tt_angle':10,\n 'tt_delay':0.0001,\n 'tt_dir':1,\n 'tt_stepsperrotation':3200,\n 'cam_focus':2838,\n 'cam_focus1':0,\n 'cam_focus2':0,\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'downscale_threshold':1000,\n 'turntable_mode':false,\n 'timeout_ringlight':300,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n}}\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 310, - "y": 800, + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, "wires": [ [ - "c77552216a8bb781" + "200d4b9951b6e066" ] ] }, { - "id": "a1f0ed7d5a9d670e", + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf", + "65518f3d4e3095e5" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", "type": "inject", - "z": "829d803b6033a693", - "name": "", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", "props": [ { "p": "overwrite", - "v": "false", + "v": "true", "vt": "bool" }, { @@ -857,11 +818,11 @@ ], "repeat": "", "crontab": "", - "once": true, + "once": false, "onceDelay": "0.1", "topic": "", - "x": 90, - "y": 800, + "x": 800, + "y": 40, "wires": [ [ "544d20f02215011a" @@ -869,88 +830,181 @@ ] }, { - "id": "c77552216a8bb781", + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 580, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", "type": "python3-function", - "z": "829d803b6033a693", - "name": "chk files", - "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", "outputs": 1, - "x": 520, - "y": 800, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 540, "wires": [ [ - "960912e90ba5b5bc" + "62cd5288.2805fc" ] ] }, { - "id": "38783aea9cc317a6", - "type": "link in", - "z": "829d803b6033a693", - "name": "factory reset", - "links": [ - "80bccc884b0be297", - "beacc3dc5398fa79" - ], - "x": 135, - "y": 840, + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 620, "wires": [ [ - "544d20f02215011a" + "62cd5288.2805fc" ] ] }, { - "id": "f20da2fc4978b7bf", - "type": "link out", - "z": "829d803b6033a693", - "name": "global", - "mode": "link", - "links": [ - "d14bbbb446d45e39" - ], - "x": 345, - "y": 400, - "wires": [] + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 540, + "wires": [ + [] + ] }, { - "id": "8e39e4a037487ecd", - "type": "python3-function", - "z": "829d803b6033a693", - "name": "create log", - "func": "import subprocess\nfrom time import sleep\nsleep(20)\n\n\nlog = '############################################DMESG############################################\\n'\nlog += subprocess.getoutput(\"dmesg\")\nlog += '\\n############################################SYSLOG############################################\\n'\nlog += subprocess.getoutput(\"tail -10000 /var/log/syslog\")\n\nwith open('/home/pi/OpenScan/tmp/log.txt', 'w+') as file:\n file.write(log)\n\nreturn msg", - "outputs": 1, - "x": 240, - "y": 560, + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 580, "wires": [ - [] + [ + "62cd5288.2805fc" + ] ] }, { - "id": "be8cae9cf6f3585f", - "type": "ui_template", - "z": "829d803b6033a693", - "group": "1f7f7e1e24f5ad9b", - "name": "first start", - "order": 1, - "width": 6, - "height": 3, - "format": "

Initial Setup

\n

Note, that you can always adjust these and other settings in the settings menu, which will appear after this setup stage. 

\n

Model

\n

Please select the OpenScan Version - this will only affect the motor settings (acceleration, gear ratio, speed).

\n

Camera

\n

- Pi Camera v1, v2, HQ, Arducam IMX519, IMX290, IMX378, OV9281 are connected through the ribbon cable. If you encounter any issues, please check the cable's orientation

\n

- DSLR (gphoto) - can be used with a wide range of cameras, which can be connected and controlled via USB. Check GPhoto if your camera is supported

\n

- External Camera - Can be used to connect your camera trigger to the GPIO pins on the front of the pi shield. This can be used with any (modified) remote shutter release, and thus it is possible to use Smartphones, DSLR and compact cameras

", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": true, - "templateScope": "local", + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", "className": "", - "x": 280, - "y": 40, + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 660, "wires": [ - [] + [ + "62cd5288.2805fc" + ] ] }, { "id": "8955d11554f55e63", "type": "ui_button", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "", "group": "5b3e5aca21140e9a", "order": 1, @@ -968,7 +1022,7 @@ "topic": "", "topicType": "str", "x": 120, - "y": 280, + "y": 720, "wires": [ [ "1e7457ea9c2c5e09" @@ -978,961 +1032,410 @@ { "id": "1e7457ea9c2c5e09", "type": "link out", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "update", "mode": "link", "links": [ "39a502b38837273d" ], "x": 245, - "y": 280, - "wires": [] - }, - { - "id": "bb84b9e5c7d8e21f", - "type": "python3-function", - "z": "829d803b6033a693", - "name": "rescue incomplete project", - "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", - "outputs": 1, - "x": 290, - "y": 600, - "wires": [ - [] - ] - }, - { - "id": "a291fc98e4269c1b", - "type": "ui_text", - "z": "829d803b6033a693", - "group": "729f9ea6e3513c9b", - "order": 7, - "width": 4, - "height": 1, - "name": "version", - "label": "Version:", - "format": "{{msg.firmware}}", - "layout": "row-center", - "className": "", - "x": 460, - "y": 360, + "y": 720, "wires": [] }, { - "id": "7113d7b25a851151", + "id": "245e4341d4fb611c", "type": "function", - "z": "829d803b6033a693", - "name": "FIRMWARE VERSION", - "func": "msg.firmware = '2022-08-02'\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 280, - "y": 360, + "x": 790, + "y": 540, "wires": [ [ - "a291fc98e4269c1b", - "ec5cefa70ff535f7" + "627406f3611511dc" ] ] }, { - "id": "ec5cefa70ff535f7", - "type": "ui_text", - "z": "829d803b6033a693", - "group": "ddbd496e.93a288", - "order": 2, - "width": 6, - "height": 1, - "name": "current version", - "label": "Current version:", - "format": "{{msg.firmware}}", - "layout": "row-spread", - "className": "", - "x": 480, - "y": 320, - "wires": [] - }, - { - "id": "c4c1580c289fc7bd", + "id": "627406f3611511dc", "type": "python3-function", - "z": "829d803b6033a693", - "name": "create path", - "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "z": "e6f4d02efb300ea9", + "name": "write", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", "outputs": 1, - "x": 250, - "y": 640, - "wires": [ - [] - ] - }, - { - "id": "06d33bb8951ce668", - "type": "ui_template", - "z": "829d803b6033a693", - "group": "", - "name": "donate", - "order": 2, - "width": "0", - "height": "0", - "format": "\n\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "global", - "className": "", - "x": 450, - "y": 40, - "wires": [ - [] - ] - }, - { - "id": "828e5298.d2192", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 9, - "width": 2, - "height": 1, - "passthru": false, - "label": "⇐", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 400, - "wires": [ - [ - "b12e54fb.3141b8" - ] - ] - }, - { - "id": "96c7e241.458e6", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 10, - "width": 2, - "height": 1, - "passthru": false, - "label": "⇒", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 440, - "wires": [ - [ - "37f52dd4.bd7572" - ] - ] - }, - { - "id": "2e854876.6b6008", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 6, - "width": 2, - "height": 1, - "passthru": true, - "label": "⇑", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 280, - "wires": [ - [ - "555aea34.b3b5e4" - ] - ] - }, - { - "id": "753817f.1b9b3e8", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 7, - "width": 2, - "height": 1, - "passthru": true, - "label": "⇓", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 320, + "x": 930, + "y": 540, "wires": [ [ - "9905e0c9.dddcd" + "50eeb3e362f9027f" ] ] }, { - "id": "8775044.3aa3ef8", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 8, - "width": 2, - "height": 1, - "name": "", - "label": "Turntable", - "format": "", - "layout": "row-left", - "className": "", - "x": 100, - "y": 360, - "wires": [] - }, - { - "id": "9e8a2d23.bf6ce", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 5, - "width": 2, - "height": 1, + "id": "88b1bddde110298a", + "type": "inject", + "z": "e6f4d02efb300ea9", "name": "", - "label": "Rotor", - "format": "", - "layout": "row-left", - "className": "", - "x": 90, - "y": 240, - "wires": [] - }, - { - "id": "555aea34.b3b5e4", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 280, - "wires": [ - [ - "46e00b45.c24ca4" - ] - ] - }, - { - "id": "9905e0c9.dddcd", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 320, - "wires": [ - [ - "6ee089cb343a35ef" - ] - ] - }, - { - "id": "b12e54fb.3141b8", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 400, - "wires": [ - [ - "c1871a2b9af5419a" - ] - ] - }, - { - "id": "37f52dd4.bd7572", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 440, - "wires": [ - [ - "42b9f1fc49e69f54" - ] - ] - }, - { - "id": "46e00b45.c24ca4", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Rotor left", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('rotor',load_int('rotor_angle'))", - "outputs": 1, - "x": 360, - "y": 280, - "wires": [ - [] - ] - }, - { - "id": "6ee089cb343a35ef", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Rotor right", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('rotor',-load_int('rotor_angle'))", - "outputs": 1, - "x": 370, - "y": 320, - "wires": [ - [] - ] - }, - { - "id": "42b9f1fc49e69f54", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "TT right", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('tt',-load_int('tt_angle'))", - "outputs": 1, - "x": 360, - "y": 440, - "wires": [ - [] - ] - }, - { - "id": "c1871a2b9af5419a", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "TT left", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('tt',load_int('tt_angle'))", - "outputs": 1, - "x": 350, - "y": 400, - "wires": [ - [] - ] - }, - { - "id": "aebad788761dce4a", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "routine_photocount", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 14, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", + "props": [ + { + "p": "overwrite", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": "0.1", "topic": "", - "topicType": "str", - "min": "10", - "max": "300", - "step": "10", - "className": "", - "x": 350, - "y": 540, - "wires": [ - [ - "ce28a0b5bfb0d5a1" - ] - ] - }, - { - "id": "107a030938cbfea9", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, + "x": 650, "y": 540, "wires": [ [ - "aebad788761dce4a" + "245e4341d4fb611c" ] ] }, { - "id": "ce28a0b5bfb0d5a1", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, + "id": "50eeb3e362f9027f", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "started1s", + "mode": "link", + "links": [ + "2f4c0f98.dee2", + "397ab7f44b893c89", + "65145c939b6647e2", + "65b38bfeb3fee710", + "6d1e12f51f9af0b6", + "788fabff98c7973c", + "9b2bc9849aee310b", + "a1e14624058e74cd", + "a67c18aaca2f5fa5", + "bd80ec228fb9a86d", + "cc9c4092edeb43cc", + "d3fc91d87d5d5f62", + "d7c1fb4c028b21a5", + "e5f38b4a07a5e278", + "f0b355967b33dfee", + "d0104e0163745993", + "5e7d5e4335d37794", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244" + ], + "x": 1015, "y": 540, - "wires": [ - [] - ] - }, - { - "id": "84d6b96c8ebaac96", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadF", - "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 580, - "wires": [ - [ - "470b10726d298834" - ] - ] - }, - { - "id": "470b10726d298834", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "shutter ", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 16, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "1", - "max": "700", - "step": "1", - "className": "", - "x": 310, - "y": 580, - "wires": [ - [ - "44c3947a9b92d32d" - ] - ] + "wires": [] }, { - "id": "44c3947a9b92d32d", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "id": "4f3121f158f06a61", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, + "x": 860, "y": 580, "wires": [ [] ] }, { - "id": "069bcf58b1fe44cd", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 13, - "width": 3, - "height": 1, - "name": "photocount", - "label": "Photos", - "format": "", - "layout": "row-left", - "className": "", - "x": 670, - "y": 540, - "wires": [] - }, - { - "id": "8dc7df1de59cb03a", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 15, - "width": 3, - "height": 1, - "name": "shutter", - "label": "Shutter (ms)", - "format": "", - "layout": "row-left", - "className": "", - "x": 650, - "y": 580, - "wires": [] - }, - { - "id": "cc69dba8d54a29dd", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "Crop X", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 18, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", + "id": "4a8a04b1e5dca8fe", + "type": "inject", + "z": "e6f4d02efb300ea9", + "name": "run rotor till endstop", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, "topic": "", - "topicType": "str", - "min": "0", - "max": "99", - "step": "1", - "className": "", - "x": 320, - "y": 620, + "payload": "", + "payloadType": "date", + "x": 690, + "y": 580, "wires": [ [ - "c2b2ab5524271123" + "4f3121f158f06a61" ] ] }, { - "id": "e3a90602605fb9e9", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "Crop Y", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 20, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0", - "max": "99", - "step": "1", + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n
    \n
  • speed improvement 2-3x
  • \n
  • currently tested on OpenScan Mini + IMX519 with RPi 4
  • \n
  • optimized toolpath
  • \n
  • more responsive user interface
  • \n
  • hotspot mode (when no wireless network available ssid: openscan pw: opensource
  • \n
  • preview features and sharpness
  • \n
  • partial background masking
  • \n
  • no more autofocus --> instead you can set a min and max focus distance
  • \n
\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", "className": "", - "x": 310, - "y": 660, + "x": 580, + "y": 260, "wires": [ - [ - "26f17a7f406df73c" - ] + [] ] }, { - "id": "9c6b48b7b4cc4e1a", + "id": "6a3d9acbe097a3d2", "type": "function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "loadI", - "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 190, - "y": 620, + "y": 120, "wires": [ [ - "cc69dba8d54a29dd" + "cb6ebdabaaf7d0da" ] ] }, { - "id": "c470fd0b15356206", + "id": "7ef6f1b5c67201fe", "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 190, - "y": 660, + "x": 510, + "y": 120, "wires": [ - [ - "e3a90602605fb9e9" - ] + [] ] }, { - "id": "c2b2ab5524271123", + "id": "86f7d1b2d763f6e2", "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 510, - "y": 620, + "x": 190, + "y": 160, "wires": [ - [] + [ + "c8a3fde5206ce1ae" + ] ] }, { - "id": "26f17a7f406df73c", + "id": "fd799c931139764d", "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 510, - "y": 660, - "wires": [ - [] - ] - }, - { - "id": "fecf5cff888bb570", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 17, - "width": 3, - "height": 1, - "name": "cropx", - "label": "{{msg.crop1}}", - "format": "", - "layout": "row-left", - "className": "", - "x": 690, - "y": 620, - "wires": [] - }, - { - "id": "0ee4950bd21498bd", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 19, - "width": 3, - "height": 1, - "name": "cropy", - "label": "{{msg.crop2}}", - "format": "", - "layout": "row-left", - "className": "", - "x": 690, - "y": 660, - "wires": [] - }, - { - "id": "ebbf11b55d758806", - "type": "ui_text_input", - "z": "1613373abaf77a2c", - "name": "", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 4, - "width": 3, - "height": 1, - "passthru": true, - "mode": "text", - "delay": "0", - "topic": "", - "sendOnBlur": true, - "className": "", - "topicType": "str", - "x": 320, - "y": 500, + "x": 190, + "y": 240, "wires": [ [ - "67385b196c517ac6" + "87be854db758a9a6" ] ] }, { - "id": "f4b3112a9ec6c487", + "id": "d5140d455122c49a", "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.payload=\"default\"\nreturn msg;", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 190, - "y": 500, + "y": 280, "wires": [ [ - "ebbf11b55d758806" + "9daea4bd57f7a00e" ] ] }, { - "id": "67385b196c517ac6", + "id": "194f3590dd4f6e3d", "type": "function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "write", - "func": "var file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 510, - "y": 500, - "wires": [ - [] - ] - }, - { - "id": "4dd7285c2b0fd79b", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "ringlight", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 12, - "width": 3, - "height": 1, - "passthru": true, - "outs": "all", - "topic": "", - "topicType": "str", - "min": 0, - "max": "3", - "step": 1, - "className": "", - "x": 320, - "y": 700, - "wires": [ - [ - "873dace18a23fdf2" - ] - ] - }, - { - "id": "873dace18a23fdf2", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "LED", - "func": "from OpenScan import ringlight\nval = msg['payload']\n\nif val == 0:\n ringlight(1,False)\n ringlight(2,False)\nelif val == 1:\n ringlight(1,False)\n ringlight(2,True)\nelif val == 2:\n ringlight(1,True)\n ringlight(2,False)\nelif val == 3:\n ringlight(1,True)\n ringlight(2,True)", - "outputs": 1, - "x": 510, - "y": 700, + "y": 240, "wires": [ [] ] }, { - "id": "9e30e33a1520fee0", + "id": "2de69452e829d780", "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "msg.payload = 0\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 190, - "y": 700, + "x": 510, + "y": 280, "wires": [ - [ - "4dd7285c2b0fd79b" - ] + [] ] }, { - "id": "7dd287f40385922f", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "start ", - "group": "7aaf184330605300", - "order": 21, - "width": 2, - "height": 1, - "passthru": false, + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", "label": "", "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-play", - "payload": "", - "payloadType": "date", - "topic": "enabled", - "topicType": "str", - "x": 150, - "y": 880, - "wires": [ - [ - "431f917c2541ae48", - "33d94a04b96a2de0", - "6d15f717d5a11002" - ] - ] - }, - { - "id": "579f2211199fd6ab", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "stop", - "group": "7aaf184330605300", - "order": 23, - "width": 2, + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-stop", - "payload": "numberofphotos", - "payloadType": "global", + "passthru": true, + "mode": "text", + "delay": "0", "topic": "", + "sendOnBlur": true, + "className": "", "topicType": "str", - "x": 810, - "y": 960, + "x": 320, + "y": 80, "wires": [ [ - "1787f08ed7070ddd", - "c1c044f3c2139f68" + "734ac3bff2df6837" ] ] }, { - "id": "431f917c2541ae48", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Routine", - "func": "from OpenScan import load_bool, load_str, load_int, load_float, motorrun, create_coordinates, take_photo, save, load_bool, camera\nfrom time import sleep, strftime, time\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system\nfrom os.path import isfile\nfrom Arducam import Focuser\n\nif load_str(\"status_internal_cam\")==\"no camera found\" or load_str(\"status_internal_cam\")[:5]==\"Featu\":\n return\n\nsave('status_internal_cam','Routine-preparing')\n\nprojectname=load_str(\"routine_projectname\")\nphotocount = load_int('routine_photocount') #vorher point_count\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nangle_start = load_int('rotor_anglestart')\ncam = load_str('camera')\nSTmode = load_bool('cam_STmode')\ntt_mode = load_bool('turntable_mode')\ncam_delay_after = load_float('cam_delay_after')\ncam_delay_before = load_float('cam_delay_before')\n\nif cam == 'imx519' and STmode == True:\n focuser = Focuser('/dev/v4l-subdev1')\n stacksize = load_int('cam_stacksize')\n focus1 = load_int('cam_focus1')\n focus2 = load_int('cam_focus2')\n if focus1 > focus2:\n focus2 = focus1\n focus1 = load_int('cam_focus2') \n focusstep = int((focus2-focus1)/(stacksize - 1))\n\ncounter = 0\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp/tmp.jpg'\nzippath = basepath + 'tmp/tmp.zip'\n\nif not 'projectcode' in msg:\n projectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n msg['projectcode'] = projectcode\n msg['counter'] = -1\n if isfile(zippath):\n system('rm ' + zippath)\n sleep(1)\n\nprojectcode = msg['projectcode']\nmsg['counter'] += 1\n\nif tt_mode == False:\n coordinates = create_coordinates(angle_min,angle_max,photocount)\nelse:\n angle_start = 0\n coordinates = []\n for i in range (photocount):\n coordinates.append([0,360/photocount*(i+1)])\n\nposition_last = (angle_start , 0)\n\nzip = ZipFile(zippath, \"a\",ZIP_DEFLATED, allowZip64=True)\n\nstarttime = time()\n\nfor position in coordinates:\n counter += 1\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n\n while load_str('status_internal_cam') == 'Routine-paused':\n sleep(0.2)\n\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n\n rotor_angle = position_last[0] - position[0]\n if abs(rotor_angle) > 180:\n rotor_angle = -360 * rotor_angle/abs(rotor_angle) + rotor_angle\n\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n # tt_angle = -360 * tt_angle/abs(tt_angle) + tt_angle\n \n motorrun('rotor', rotor_angle)\n motorrun('tt', tt_angle)\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n while load_str('status_internal_cam') == 'Routine-paused':\n sleep(0.2)\n\n msg['cropx'] = load_int('cam_cropx')\n msg['cropy'] = load_int('cam_cropy')\n msg['rotation'] = load_int('cam_rotation')\n msg['filepath_in'] = 'tmp/tmp.jpg'\n msg['filepath_out'] = 'tmp/tmp.jpg'\n msg['filepath'] = 'tmp/tmp.jpg'\n\n if counter < 6:\n ETA = ''\n sleep(cam_delay_before)\n if STmode == True:\n counter2 = 0\n for focus in range (stacksize):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n while load_str('status_internal_cam') == 'Routine-paused':\n sleep(0.2)\n counter2 += 1\n save('status_internal_cam','Routine-' + str(counter) + '/' + str(photocount) + ' F' + str(counter2) + ETA)\n focuser.write(focus1 + focus * focusstep)\n take_photo('tmp/tmp.jpg')\n camera('/crop',msg)\n zip.write(temppath, projectname + '_' + str(msg['counter']) + '_' + str(counter) + '-' + str(focus) + \".jpg\")\n system('cp ' + temppath + ' ' + basepath +'tmp/preview.jpg')\n elif cam != 'external':\n save('status_internal_cam','Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n\n if cam == 'gphoto':\n camera('/gphoto_capture', msg)\n if cam in ('usb_webcam','imx219','ov5647','imx477','imx290a','imx290b','imx378','ov9281','imx519'):\n take_photo('tmp/tmp.jpg')\n camera('/crop',msg)\n \n zip.write(temppath, projectname + '_' + str(msg['counter']) + '_' + str(counter) + \".jpg\")\n system('cp ' + temppath + ' ' + basepath +'tmp/preview.jpg')\n elif cam == 'external':\n camera('external_capture')\n save('status_internal_cam','Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n\n ETA = '-ETA:'+str(int((photocount/counter - 1)*(time() - starttime)))+'/'+str(int(photocount/counter*(time() - starttime)))+'s'\n sleep(cam_delay_after)\n\n position_last = position\n\nzip.close()\n\nsave('status_internal_cam','Routine-done')\n\nmotorrun('rotor',position_last[0] - angle_start)\nmotorrun('tt',position_last[1])\n\nsave('status_internal_cam','--READY--')\n\nif load_bool('routine_secondpass')==True:\n msg['topic'] = 'Scan done'\n msg['payload'] = 'Do you want to run another pass or finish this project?'\n msg['enabled'] = False\n return msg,None\n\nreturn None,msg\n", - "outputs": 2, - "x": 300, - "y": 880, + "id": "97170908e1f4ac55", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 80, "wires": [ [ - "db7eea74d3bf892b" - ], - [ - "0b8661103366f834" + "58e565fea35cb667" ] ] }, { - "id": "1787f08ed7070ddd", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "stop", - "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "id": "734ac3bff2df6837", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, - "x": 930, - "y": 960, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 80, "wires": [ [] ] }, { - "id": "e9b13dfd9f8d3711", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", "links": [ - "8367cfa0bf5bc5df", - "b33d604c.5f1a6" + "960912e90ba5b5bc", + "50eeb3e362f9027f" ], - "x": 395, - "y": 840, - "wires": [] + "x": 55, + "y": 80, + "wires": [ + [ + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" + ] + ] }, { - "id": "9654deebb668e012", + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", + "outputs": 1, + "x": 510, + "y": 200, + "wires": [ + [] + ] + }, + { + "id": "c7f5808d753480d4", "type": "inject", - "z": "1613373abaf77a2c", - "name": "1s", + "z": "481edaf6db5a7a54", + "name": "", "props": [ { "p": "payload" @@ -1945,80 +1448,63 @@ "repeat": "", "crontab": "", "once": true, - "onceDelay": "1", + "onceDelay": "6", "topic": "", "payload": "", "payloadType": "date", - "x": 290, - "y": 1000, + "x": 170, + "y": 200, "wires": [ [ - "c1c044f3c2139f68" + "11f41a6030578ef4" ] ] }, { - "id": "8367cfa0bf5bc5df", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "start routine", - "links": [ - "210ef5246d1a8790", - "84608db962fd9932", - "8689e938.dd9e38", - "f20f2dbc.0f123", - "e9b13dfd9f8d3711", - "96bdb9417e38810f", - "fb13752beddee9f2", - "bd75f33b8a57c522" - ], - "x": 55, - "y": 880, + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 310, + "y": 200, "wires": [ [ - "7dd287f40385922f" + "a0156eaac7dd35e5" ] ] }, { - "id": "fb13752beddee9f2", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", - "links": [ - "2f4c0f98.dee2", - "8367cfa0bf5bc5df", - "b33d604c.5f1a6" - ], - "x": 895, - "y": 920, - "wires": [] - }, - { - "id": "95439678bb2df2a2", + "id": "855cbcadef1163c5", "type": "function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "enable", - "func": "msg.flag = global.get('flag')\nif (global.get('flag_pw')== true){\n return msg\n}\n", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 230, - "y": 1220, + "x": 250, + "y": 840, "wires": [ [ - "04cc2467807d2d6b", - "14f9617b5b301318" + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" ] ] }, { - "id": "948a3ae4444685f2", + "id": "1a443e20a973d2f1", "type": "change", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "flag_pw true", "rules": [ { @@ -2034,16 +1520,16 @@ "from": "", "to": "", "reg": false, - "x": 610, - "y": 1260, + "x": 630, + "y": 760, "wires": [ [] ] }, { - "id": "04cc2467807d2d6b", + "id": "d1b87196ae5373ed", "type": "change", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "flag_pw false", "rules": [ { @@ -2059,79 +1545,16 @@ "from": "", "to": "", "reg": false, - "x": 390, - "y": 1260, - "wires": [ - [] - ] - }, - { - "id": "12f1399b240830bf", - "type": "exec", - "z": "1613373abaf77a2c", - "command": " v4l2-ctl --list-formats-ext", - "addpay": "", - "append": "", - "useSpawn": "true", - "timer": "", - "winHide": false, - "oldrc": false, - "name": "check cam", - "x": 190, - "y": 100, + "x": 430, + "y": 760, "wires": [ - [ - "6222f781629c72e7" - ], - [ - "6222f781629c72e7" - ], [] ] }, { - "id": "6222f781629c72e7", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\ncontent = '--READY--'\n\nif (msg.payload.includes('Cannot open device')){\n content = 'no camera found'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return msg\n }\n });\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 350, - "y": 100, - "wires": [ - [ - "e89c16809f8a5f1c" - ] - ] - }, - { - "id": "e978bf8c53d1f15a", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "Settings internal cam", - "info": "", - "x": 120, - "y": 40, - "wires": [] - }, - { - "id": "ccb7da246de908d1", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "preview internal cam", - "info": "", - "x": 110, - "y": 1160, - "wires": [] - }, - { - "id": "e9566588c5e40637", + "id": "03d92601c62b79d4", "type": "inject", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "4s/0.5", "props": [ { @@ -2142,1271 +1565,1127 @@ "vt": "str" } ], - "repeat": "0.5", + "repeat": "0.1", "crontab": "", "once": true, "onceDelay": "4", "topic": "Repeat", - "payload": "0.2", + "payload": "0.1", "payloadType": "str", - "x": 80, - "y": 1220, + "x": 100, + "y": 840, "wires": [ [ - "95439678bb2df2a2" + "855cbcadef1163c5" ] ] }, { - "id": "14f9617b5b301318", + "id": "41e6a4649b6afbfb", "type": "python3-function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "Take Preview Shot", - "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nsleep(0.5)\n\n\nstatus = load_str('status_internal_cam')\ncam=load_str('camera')\n\n\nif msg['flag'] == False and not 'Routine' in status:\n return msg\n\nif cam == 'external':\n return\n\nmsg['payload']=\"/tmp/preview.jpg?ts=\"+str(int(time()*10))\n\nif cam == 'gphoto' and status == 'no camera found':\n if camera('/gphoto_init') == 200:\n save('status_internal_cam','--READY--')\n\nif status!=\"--READY--\":\n return msg\n\nmsg['cropx'] = load_int('cam_cropx')\nmsg['cropy'] = load_int('cam_cropy')\nmsg['rotation'] = load_int('cam_rotation')\nmsg['filepath_in'] = 'tmp/tmp.jpg'\nmsg['filepath_out'] = 'tmp/preview.jpg'\nmsg['filepath'] = 'tmp/tmp.jpg'\nmsg['preview'] = True\n\nif cam == 'gphoto':\n if camera('/gphoto_test', msg) != 200:\n save('status_internal_cam','no camera found')\n return msg\n camera('/gphoto_preview', msg)\n\nif cam in ('usb_webcam', 'imx219','ov5647','imx477','imx290a','imx290b','imx378','ov9281','imx519'):\n take_photo('tmp/tmp.jpg')\n\ncamera('/crop',msg)\n\nreturn msg\n", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/picam2_take_photo')\n\nreturn msg\n", "outputs": 1, - "x": 410, - "y": 1220, + "x": 450, + "y": 800, "wires": [ [ - "948a3ae4444685f2", - "991b587d406d0d91", - "8f5d87ce24c40b11" + "1a443e20a973d2f1", + "296636b7467fc745" ] ] }, { - "id": "991b587d406d0d91", + "id": "85a268108250ba88", "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "ce9cc9d915dc6eb6", - "name": "preview_internal", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", "order": 1, - "width": 12, - "height": 12, - "format": "
\n\n\n
\n", + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", "storeOutMessages": false, "fwdInMessages": false, "resendOnRefresh": false, "templateScope": "local", "className": "", - "x": 620, - "y": 1220, - "wires": [ - [] - ] - }, - { - "id": "1118d0965ff7c40b", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 3, - "width": 3, - "height": 1, - "name": "projectname", - "label": "Projectname", - "format": "", - "layout": "row-left", - "className": "", - "x": 670, - "y": 500, - "wires": [] - }, - { - "id": "82c8ad50ecfbc755", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 11, - "width": 3, - "height": 1, - "name": "ringlight", - "label": "Ringlight", - "format": "", - "layout": "row-left", - "className": "", - "x": 660, - "y": 700, - "wires": [] - }, - { - "id": "33d94a04b96a2de0", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 960, - "wires": [ - [ - "579f2211199fd6ab", - "c433515042ba01b5" - ] - ] - }, - { - "id": "c1c044f3c2139f68", - "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.enabled = false\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 810, - "y": 1000, + "x": 450, + "y": 840, "wires": [ [ - "579f2211199fd6ab", - "c433515042ba01b5" + "417f653ca0dfdcfc", + "180476141c2a44ad" ] ] }, { - "id": "9a368472a72fbc48", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "preview arducam with focus", - "info": "", - "x": 140, - "y": 1360, + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, "wires": [] }, { - "id": "8f5d87ce24c40b11", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "preview_arducam", - "order": 2, - "width": 10, - "height": 12, - "format": "
\n\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 630, - "y": 1300, + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, "wires": [ - [] + [ + "e864254b18c23dd1" + ] ] }, { - "id": "282efe64332193c8", + "id": "e864254b18c23dd1", "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "focus", - "func": "from OpenScan import load_str\n\nif load_str('camera') != 'imx519':\n return\n\nfrom Arducam import Focuser\n\n\nif msg['focuser'] == True:\n focuser = Focuser('/dev/v4l-subdev1')\n focuser.write(msg['focus'])\n return msg", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int\n\nif 'payload' not in msg:\n return\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'))\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'))\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'))\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'))\n\n", "outputs": 1, - "x": 1110, - "y": 1460, + "x": 780, + "y": 840, "wires": [ [] ] }, { - "id": "64b16ef47ab6d859", - "type": "ui_switch", - "z": "1613373abaf77a2c", - "name": "MF", - "label": "", - "tooltip": "", - "group": "90223f7ddc082321", - "order": 4, - "width": 1, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "topic", - "topicType": "msg", - "style": "", - "onvalue": "false", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "true", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 150, - "y": 1400, - "wires": [ - [ - "f017f67a8d4a3750" - ] - ] - }, - { - "id": "f017f67a8d4a3750", + "id": "180476141c2a44ad", "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "let fs = global.get('fs');\nfilepath = '/home/pi/OpenScan/settings/';\n\nvar file = 'status_internal_cam'\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data != '--READY--'){\n return\n}\n\nfile = 'cam_AFmode'\ncontent = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});\n\nglobal.set('AF',msg.payload)\nmsg.enabled = false\nif (msg.payload == false){\n msg.enabled = true\n}\nif (msg.payload == true){\n file = 'cam_focus1'\n content = String(0)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n file = 'cam_focus2'\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n \n file = 'cam_stacksize'\n content = String(2)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n global.set('focus1', 0)\n global.set('focus2', 0)\n\n}\n\n\nmsg.focus = global.get('focus')\nmsg.payload = 'down'\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 1400, + "x": 630, + "y": 880, "wires": [ [ - "5c39bd09.702d84", - "74521cf72050b515", - "b70e8c24ee011258", - "a2ff9dfd858821bc", - "ef62086d10d830fd" + "8cbdbfecbd12ef83" ] ] }, { - "id": "65145c939b6647e2", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "", - "links": [ - "960912e90ba5b5bc" - ], - "x": 55, - "y": 1400, + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", + "outputs": 1, + "x": 870, + "y": 880, "wires": [ - [ - "64b16ef47ab6d859" - ] + [] ] }, { - "id": "5ea18678.975138", - "type": "trigger", - "z": "1613373abaf77a2c", - "name": "20ms", - "op1": "", - "op2": "0", - "op1type": "pay", - "op2type": "str", - "duration": "-20", - "extend": false, - "overrideDelay": false, - "units": "ms", - "reset": "", - "bytopic": "all", - "topic": "topic", + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", "outputs": 1, - "x": 730, - "y": 1440, + "x": 440, + "y": 720, "wires": [ [ - "fd93843e238cc9ce" + "923be3b2b25224b4" ] ] }, { - "id": "5c39bd09.702d84", + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, + "wires": [ + [] + ] + }, + { + "id": "c8a3fde5206ce1ae", "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "F+", - "order": 8, - "width": 1, + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, "height": 1, - "format": " ", + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", "storeOutMessages": true, "fwdInMessages": true, - "resendOnRefresh": false, + "resendOnRefresh": true, "templateScope": "local", "className": "", - "x": 410, - "y": 1400, + "x": 310, + "y": 160, "wires": [ [ - "dcfb5cce.0431a" + "034ec9f59e50a361", + "a0156eaac7dd35e5" ] ] }, { - "id": "dcfb5cce.0431a", - "type": "switch", - "z": "1613373abaf77a2c", - "name": "", - "property": "payload", - "propertyType": "msg", - "rules": [ - { - "t": "eq", - "v": "1", - "vt": "num" - }, - { - "t": "eq", - "v": "-1", - "vt": "num" - }, - { - "t": "eq", - "v": "up", - "vt": "str" - } - ], - "checkall": "true", - "repair": false, - "outputs": 3, - "x": 550, - "y": 1420, + "id": "034ec9f59e50a361", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, "wires": [ [ - "5ea18678.975138", - "f4a41b1e7b221486" - ], - [ - "5ea18678.975138", - "f4a41b1e7b221486" - ], - [ - "8cdd0a6b.40bcd8" + "194f3590dd4f6e3d" ] ] }, { - "id": "8cdd0a6b.40bcd8", - "type": "change", - "z": "1613373abaf77a2c", - "name": "", - "rules": [ - { - "t": "set", - "p": "reset", - "pt": "msg", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 560, - "y": 1480, + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, "wires": [ [ - "5ea18678.975138", - "e9b3837b1ffb0360" + "2de69452e829d780" ] ] }, { - "id": "74521cf72050b515", + "id": "cb6ebdabaaf7d0da", "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "F-", - "order": 9, - "width": 1, + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, "height": 1, - "format": " ", + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", "storeOutMessages": true, "fwdInMessages": true, - "resendOnRefresh": false, + "resendOnRefresh": true, "templateScope": "local", "className": "", - "x": 410, - "y": 1440, + "x": 320, + "y": 120, "wires": [ [ - "dcfb5cce.0431a" + "7ef6f1b5c67201fe" ] ] }, { - "id": "7219f62c9fdc6753", + "id": "82ecd3cd971cb7ea", "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 7, - "width": 2, + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, "height": 1, - "name": "", - "label": "{{msg.payload}}", + "name": "projectname", + "label": "Projectname", "format": "", - "layout": "col-center", + "layout": "row-left", "className": "", - "x": 1130, - "y": 1420, + "x": 530, + "y": 40, "wires": [] }, { - "id": "b70e8c24ee011258", - "type": "function", - "z": "1613373abaf77a2c", - "name": "global", - "func": "if (msg.payload == 'down'){\n msg.enabled = false\n msg.payload = ' '\n msg.focuser = global.get('focuser')\n return msg\n}\n\n\nmsg.enabled = true\n\nsign = msg.payload\nfocus = global.get('focus')\nif (focus > 3000){\n focusstep = 5\n}\nelse if (focus <=3000 && focus > 2000){\n focusstep = 3\n}\nelse{\n focusstep = 2\n}\n\n\nfocus = focus + sign * focusstep\n\nsign = msg.payload\nif (focus > 4000){\n distance = 6\n focus = 4000\n}\nelse if (focus > 1200 && focus <= 4000){\n distance = 737086 * Math.pow(focus, -1.4096)\n}\nelse if (focus <= 1200){\n distance = 999\n if (focus <=0){\n focus = 0\n }\n}\n\n\nglobal.set('focus', focus)\nmsg.focus = focus\nmsg.distance = distance\ndistance = distance * 10\nmsg.focuser = global.get('focuser')\nmsg.payload = String(distance.toFixed(1)) + 'mm'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 970, - "y": 1440, + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, "wires": [ [ - "7219f62c9fdc6753", - "282efe64332193c8", - "704a9f89089d1f25" + "06e1e19835a9816e" ] ] }, { - "id": "f4a41b1e7b221486", - "type": "change", - "z": "1613373abaf77a2c", - "name": "focuser f", - "rules": [ - { - "t": "set", - "p": "focuser", - "pt": "global", - "to": "false", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 740, - "y": 1400, + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, "wires": [ - [] + [ + "1fe18f3b0b52aabd" + ] ] }, { - "id": "e9b3837b1ffb0360", - "type": "change", - "z": "1613373abaf77a2c", - "name": "focuser t", - "rules": [ - { - "t": "set", - "p": "focuser", - "pt": "global", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 740, - "y": 1480, + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, "wires": [ [] ] }, { - "id": "fd93843e238cc9ce", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "10ms", - "pauseType": "delay", - "timeout": "20", - "timeoutUnits": "milliseconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": false, - "allowrate": false, + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, - "x": 850, - "y": 1440, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, "wires": [ [ - "b70e8c24ee011258" + "ed2974731fb8a84e" ] ] }, { - "id": "25c4138bddb77b6b", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "set", + "id": "7dd287f40385922f", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "start ", + "group": "365a30d0dfa83e95", "order": 10, "width": 2, "height": 1, - "format": "set", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", "className": "", - "x": 570, - "y": 1540, + "icon": "fa-play", + "payload": "", + "payloadType": "date", + "topic": "enabled", + "topicType": "str", + "x": 130, + "y": 1040, "wires": [ [ - "95e1d239988b29e0" + "33d94a04b96a2de0", + "6d15f717d5a11002", + "9a6b30a0175a8ecd" ] ] }, { - "id": "95e1d239988b29e0", - "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "focus = global.get('focus')\nfocus1 = global.get('focus1')\nfocus2 = global.get('focus2')\nlet fs = global.get('fs');\nfilepath = '/home/pi/OpenScan/settings/';\n \nif (msg.payload == false){\n return msg\n}\n\nif (focus1 != 0 && focus2 != 0){\n global.set('focus1', 0)\n global.set('focus2', 0)\n file = 'cam_focus1'\n content = String(0)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n file = 'cam_focus2'\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n msg.distance1 = ' '\n msg.distance2 = ' '\n msg.enabled = false\n return msg\n}\n\nif (focus > 4000){\n distance = 6\n focus = 4000\n}\nelse if (focus > 1200 && focus <= 4000){\n distance = 737086 * Math.pow(focus, -1.4096)\n}\nelse if (focus <= 1200){\n distance = 999.9\n if (focus <=0){\n focus = 0\n }\n}\ndistance = distance * 10\n\nif (focus1 == 0){\n global.set('focus1', focus)\n file = 'cam_focus1'\n content = String(focus)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n global.set('distance1', distance)\n msg.distance1 = distance.toFixed(1)\n msg.distance2 = 'tbd'\n msg.enabled = false\n return msg\n}\nif (focus1 != 0 && focus2 ==0 && focus!= focus1){\n global.set('focus2', focus)\n file = 'cam_focus2'\n content = String(focus)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n global.set('distance2', distance)\n msg.distance1 = global.get('distance1').toFixed(1)\n msg.distance2 = distance.toFixed(1)\n msg.enabled = true\n return msg\n}\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 710, - "y": 1560, + "id": "579f2211199fd6ab", + "type": "ui_button", + "z": "481edaf6db5a7a54", + "name": "stop", + "group": "365a30d0dfa83e95", + "order": 12, + "width": 2, + "height": 1, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "fa-stop", + "payload": "numberofphotos", + "payloadType": "global", + "topic": "", + "topicType": "str", + "x": 490, + "y": 1100, "wires": [ [ - "7889245e91ddea4b", - "210ef5246d1a8790" + "1787f08ed7070ddd", + "c1c044f3c2139f68" ] ] }, { - "id": "7889245e91ddea4b", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 11, - "width": 2, - "height": 1, + "id": "1787f08ed7070ddd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "stop", + "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", + "outputs": 1, + "x": 630, + "y": 1100, + "wires": [ + [] + ] + }, + { + "id": "e9b13dfd9f8d3711", + "type": "link out", + "z": "481edaf6db5a7a54", "name": "", - "label": "{{msg.distance1}}", - "format": "{{msg.distance2}}", - "layout": "col-center", - "className": "", - "x": 830, - "y": 1600, + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "c8b93b42c720b9cf" + ], + "x": 395, + "y": 1000, "wires": [] }, { - "id": "a1d29e56599da0bd", + "id": "9654deebb668e012", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "1s", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "1", + "topic": "", + "payload": "", + "payloadType": "date", + "x": 290, + "y": 1140, + "wires": [ + [ + "c1c044f3c2139f68" + ] + ] + }, + { + "id": "8367cfa0bf5bc5df", "type": "link in", - "z": "1613373abaf77a2c", - "name": "focusnumber", + "z": "481edaf6db5a7a54", + "name": "start routine", "links": [ - "210ef5246d1a8790", - "2dd2503d7ab0214b", - "6b94bf2295b1b31d" + "200d4b9951b6e066", + "8689e938.dd9e38", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" ], - "x": 175, - "y": 1760, + "x": 45, + "y": 1040, "wires": [ [ - "06504f47ee1744d7", - "5f8b90ef08a7d68c" + "7dd287f40385922f" ] ] }, { - "id": "210ef5246d1a8790", + "id": "fb13752beddee9f2", "type": "link out", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "", "mode": "link", "links": [ - "a1d29e56599da0bd", + "2f4c0f98.dee2", "8367cfa0bf5bc5df", - "149e2e46b9623a2d" + "b33d604c.5f1a6", + "c8b93b42c720b9cf" ], - "x": 835, - "y": 1560, + "x": 525, + "y": 1040, "wires": [] }, { - "id": "b6f37e23f2491639", - "type": "ui_switch", - "z": "1613373abaf77a2c", - "name": "Stack", - "label": "", - "tooltip": "", - "group": "90223f7ddc082321", - "order": 6, - "width": 1, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "topic", - "topicType": "msg", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 290, - "y": 1600, - "wires": [ - [ - "2d66216fee29250c" - ] - ] - }, - { - "id": "a2ff9dfd858821bc", + "id": "33d94a04b96a2de0", "type": "function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "enable", - "func": "msg.payload = false\nif (msg.enabled == false){\n return msg\n}\n", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 410, - "y": 1560, + "x": 290, + "y": 1100, "wires": [ [ - "25c4138bddb77b6b", - "7889245e91ddea4b", - "4cfada2de1c5bb74", - "95e1d239988b29e0" + "579f2211199fd6ab" ] ] }, { - "id": "2d66216fee29250c", + "id": "c1c044f3c2139f68", "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "file = 'cam_STmode'\nlet fs = global.get('fs');\nfilepath = '/home/pi/OpenScan/settings/';\ncontent = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});\n\nmsg.enabled = true\nglobal.set('ST',msg.payload)\nif (msg.payload == false){\n global.set('focus1',0)\n global.set('focus2',0)\n file = 'cam_focus1'\n content = String(0)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n file = 'cam_focus2'\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n \n \n msg.enabled = false\n}\nreturn msg\n", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 430, - "y": 1600, + "x": 490, + "y": 1140, "wires": [ [ - "25c4138bddb77b6b", - "7889245e91ddea4b", - "2dd2503d7ab0214b", - "4cfada2de1c5bb74" + "579f2211199fd6ab" ] ] }, { - "id": "ef62086d10d830fd", + "id": "1daf9e3a5bd5ab48", "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "msg.payload = false\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 150, - "y": 1560, + "x": 430, + "y": 1040, "wires": [ [ - "b6f37e23f2491639", - "523019d0a2c698f5" + "fb13752beddee9f2" ] ] }, { - "id": "06504f47ee1744d7", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 12, - "width": 2, - "height": 1, - "name": "", - "label": "Stacksize:", - "format": "{{msg.stacksize}}", - "layout": "row-center", - "className": "", - "x": 710, - "y": 1760, - "wires": [] - }, - { - "id": "2dd2503d7ab0214b", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", - "links": [ - "a1d29e56599da0bd" - ], - "x": 535, - "y": 1620, - "wires": [] - }, - { - "id": "21306d6402225553", + "id": "6d15f717d5a11002", "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.stacksize = msg.payload\nmsg.enabled = true\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 550, - "y": 1720, + "x": 280, + "y": 1000, "wires": [ [ - "06504f47ee1744d7", - "ca184d58f7deb4b1", - "84608db962fd9932" + "e9b13dfd9f8d3711" ] ] }, { - "id": "e2f8fdd47bdd1b66", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "stacksize", - "label": " ", - "tooltip": "", - "group": "90223f7ddc082321", - "order": 13, - "width": 2, - "height": 1, - "passthru": true, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "2", - "max": "20", - "step": "1", - "className": "", - "x": 400, - "y": 1720, + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "from OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\n\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\n#motorrun('rotor', 140, ES_enable=True, ES_start_state=True)\n#motorrun('rotor', 10)\n\n\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/picam2_switch_mode?mode=1')\n\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\n\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nif load_bool('rotor_enable_endstop'):\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True, False)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\n\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n\n motorrun('tt',tt_angle)\n motorrun('rotor',rotor_angle)\n return\n\n # THE FOLLOWING DOES NOT WORK PROPERLY WITH THREADING ?!\n\n #tt_thread = threading.Thread(target=motorrun, args=('tt', tt_angle))\n #rotor_thread = threading.Thread(target=motorrun, args=('rotor', rotor_angle))\n #tt_thread.start()\n #rotor_thread.start()\n #tt_thread.join()\n #rotor_thread.join()\n\n\ncounter2 = 0\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\n\nsystem('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, "wires": [ [ - "21306d6402225553" + "1daf9e3a5bd5ab48", + "795c85ad4f109567" ] ] }, { - "id": "523019d0a2c698f5", + "id": "afe47a9eaae6f67f", "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 5, - "width": 1, + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, "height": 1, "name": "", - "label": "St", - "format": "", - "layout": "col-center", - "className": "", - "x": 290, - "y": 1560, - "wires": [] - }, - { - "id": "dfbfe28bac5c4221", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 3, - "width": 1, - "height": 1, - "name": "MF", - "label": "MF", - "format": "", - "layout": "col-center", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", "className": "", - "x": 150, - "y": 1440, + "x": 340, + "y": 40, "wires": [] }, { - "id": "ca184d58f7deb4b1", - "type": "function", - "z": "1613373abaf77a2c", - "name": "save", - "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.stacksize)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 690, - "y": 1720, - "wires": [ - [] - ] - }, - { - "id": "704a9f89089d1f25", + "id": "8608517d0567d63f", "type": "function", - "z": "1613373abaf77a2c", - "name": "save", - "func": "var file = 'cam_focus'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.focus)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 1110, - "y": 1500, + "x": 190, + "y": 40, "wires": [ - [] + [ + "afe47a9eaae6f67f" + ] ] }, { - "id": "5f8b90ef08a7d68c", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 1720, + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" + ], + "x": 55, + "y": 40, "wires": [ [ - "e2f8fdd47bdd1b66" + "8608517d0567d63f" ] ] }, { - "id": "4cfada2de1c5bb74", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "if (msg.enabled == true){\n msg.enabled = false\n}\nelse{\n msg.enabled = true\n}\nreturn msg\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 570, - "y": 1660, + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, "wires": [ [ - "84608db962fd9932" + "9774e7ad3b506354" ] ] }, { - "id": "84608db962fd9932", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "149e2e46b9623a2d" - ], - "x": 675, - "y": 1660, - "wires": [] - }, - { - "id": "e89c16809f8a5f1c", + "id": "9774e7ad3b506354", "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "gphoto", - "func": "\nfrom OpenScan import camera, save, load_str\n\nif load_str('camera') == 'gphoto':\n if camera('/gphoto_init') == 200:\n if camera('/gphoto_test') == 200:\n save('status_internal_cam','--READY--')\n return msg\nif load_str('camera') == 'external':\n save('status_internal_cam','--READY--')", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", "outputs": 1, - "x": 490, - "y": 100, + "x": 510, + "y": 380, "wires": [ - [] + [ + "f0af909f3e739b22" + ] ] }, { - "id": "917a194be245384a", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable projectname", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 540, + "id": "39c744466a21735e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 40, "wires": [ [ - "f4b3112a9ec6c487" + "fa181d22775c2ce6" ] ] }, { - "id": "65cef204b16f8741", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable shutter", - "links": [ - "2d76e5617f13cd6c", - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 580, + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 990, + "y": 80, "wires": [ [ - "84d6b96c8ebaac96" + "c615034ea6b26174" ] ] }, { - "id": "2aea1727dbea76ce", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable cropx", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 620, + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 480, "wires": [ [ - "9c6b48b7b4cc4e1a" + "237c2135cdad86ea" ] ] }, { - "id": "4f212b44aa487945", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable cropy", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 660, + "id": "dd7fb8791d34c751", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 880, "wires": [ [ - "c470fd0b15356206" + "180476141c2a44ad" ] ] }, { - "id": "6d1e12f51f9af0b6", + "id": "5baf89a2682265f7", "type": "link in", - "z": "1613373abaf77a2c", - "name": "start camchk", + "z": "481edaf6db5a7a54", + "name": "enable led", "links": [ - "960912e90ba5b5bc" + "eb1a2387a1eeea76" ], - "x": 55, - "y": 100, + "x": 145, + "y": 880, "wires": [ [ - "12f1399b240830bf" + "dd7fb8791d34c751" ] ] }, { - "id": "8ebd1dcb5db156ed", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 2, - "width": 6, - "height": 1, - "name": "", - "label": "Current Status:", - "format": " {{msg.payload}} ", - "layout": "row-spread", - "className": "", - "x": 320, - "y": 160, - "wires": [] - }, - { - "id": "94a7aec739f9266b", + "id": "6a26e8a7253d708c", "type": "function", - "z": "1613373abaf77a2c", - "name": "loadS", - "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 160, + "x": 830, + "y": 40, "wires": [ [ - "8ebd1dcb5db156ed" + "39c744466a21735e" ] ] }, { - "id": "2415272f42ce468c", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "start status", - "links": [ - "6c6ef2255a7d39e5" - ], - "x": 55, - "y": 160, + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, "wires": [ [ - "94a7aec739f9266b" + "61aab497fa50898e" ] ] }, { - "id": "a1e14624058e74cd", + "id": "9fd259de91de1da1", "type": "link in", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "start routine settings", "links": [ - "960912e90ba5b5bc" + "960912e90ba5b5bc", + "50eeb3e362f9027f" ], - "x": 55, - "y": 500, + "x": 735, + "y": 40, "wires": [ [ - "f4b3112a9ec6c487", - "107a030938cbfea9", - "84d6b96c8ebaac96", - "9c6b48b7b4cc4e1a", - "c470fd0b15356206", - "9e30e33a1520fee0", - "79ecb889f7113405" + "6a26e8a7253d708c", + "35ad7e55833836c1" ] ] }, { - "id": "1daf9e3a5bd5ab48", + "id": "fa181d22775c2ce6", "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "global.set('flag_pw', true)\nglobal.set('flag', true)\nmsg.enabled = true\nreturn msg\n", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 810, - "y": 920, + "x": 1150, + "y": 40, "wires": [ [ - "fb13752beddee9f2" + "ae5ee8787145906d" ] ] }, { - "id": "6d15f717d5a11002", + "id": "c615034ea6b26174", "type": "function", - "z": "1613373abaf77a2c", - "name": "disable", - "func": "msg.enabled = false\nreturn msg\n", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 300, - "y": 840, + "x": 1150, + "y": 80, "wires": [ [ - "e9b13dfd9f8d3711" + "ae5ee8787145906d" ] ] }, { - "id": "d14bbbb446d45e39", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "preview", - "links": [ - "f20da2fc4978b7bf" - ], - "x": 135, - "y": 1260, + "id": "ae5ee8787145906d", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import camera\ncamera('/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", + "outputs": 1, + "x": 1290, + "y": 60, "wires": [ - [ - "95439678bb2df2a2" - ] + [] ] }, { - "id": "db7eea74d3bf892b", - "type": "ui_toast", - "z": "1613373abaf77a2c", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "Finish", - "cancel": "2nd pass", - "raw": false, - "className": "", - "topic": "", + "id": "f0af909f3e739b22", + "type": "ui_switch", + "z": "481edaf6db5a7a54", "name": "", - "x": 510, - "y": 880, + "label": "Show Features", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 420, "wires": [ [ - "0b8661103366f834" + "710fc2dbb5ef0167" ] ] }, { - "id": "0b8661103366f834", + "id": "710fc2dbb5ef0167", "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "continue", - "func": "from os import system\nfrom os.path import isfile\n\n\nif msg['payload'] == '2nd pass':\n msg['enabled'] = True\n return msg,None\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp/tmp.jpg'\nzippath = basepath + 'tmp/tmp.zip'\nprojectcode = msg['projectcode']\n\nsystem('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')\n\nmsg['path'] = basepath + 'scans/' + projectcode + '.zip'\n\nif isfile(zippath):\n system('rm ' + zippath)\n\nreturn None, msg", - "outputs": 2, - "x": 660, - "y": 920, + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, "wires": [ [ - "431f917c2541ae48", - "579f2211199fd6ab", - "c433515042ba01b5" - ], - [ - "1daf9e3a5bd5ab48", - "579f2211199fd6ab", - "c433515042ba01b5" + "78cfe60013a1bea4" ] ] }, { - "id": "79ecb889f7113405", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "inactive", - "func": "from requests import get\nfrom OpenScan import load_int\n\ntimeout = load_int('timeout_ringlight')\n\nmsg['cmd'] = 'get'\n\ntry:\n flask = 'http://127.0.0.1:1312/ping'\n r = get(flask, params=msg)\n\n idle = float(r.text.split(\":\")[1].split('}')[0])\n\n msg['payload'] = idle\n\n if idle > timeout:\n return msg,msg\nexcept:\n pass\n\nreturn None,msg", - "outputs": 2, - "x": 200, - "y": 740, + "id": "d93c2b67bcf23b9a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 480, "wires": [ [ - "9e30e33a1520fee0" - ], - [ - "8d7e04531c34f349" + "5e83b653850fa16e" ] ] }, { - "id": "8d7e04531c34f349", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "", - "pauseType": "delay", - "timeout": "30", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": false, - "allowrate": false, + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, - "x": 200, - "y": 780, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] + ] + }, + { + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 95, + "y": 480, "wires": [ [ - "79ecb889f7113405" + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" ] ] }, { - "id": "c433515042ba01b5", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "pause", - "group": "7aaf184330605300", - "order": 22, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-pause", - "payload": " ", - "payloadType": "str", - "topic": "Scan paused", - "topicType": "str", - "x": 810, - "y": 1040, + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, "wires": [ [ - "63db399d8ac2acb6" + "ed2974731fb8a84e" ] ] }, { - "id": "63db399d8ac2acb6", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "pause", - "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nif status == 'Routine-paused':\n save('status_internal_cam', 'Routine-continue')\nelse:\n save('status_internal_cam', 'Routine-paused')", - "outputs": 1, - "x": 930, - "y": 1040, + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "false", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, "wires": [ - [] + [ + "ed2974731fb8a84e" + ] ] }, { - "id": "44c598049cd533fd", + "id": "c8b93b42c720b9cf", "type": "link in", - "z": "1613373abaf77a2c", - "name": "crop", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", "links": [ - "f358de1e64b491bb" + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" ], - "x": 595, - "y": 640, + "x": 85, + "y": 380, "wires": [ [ - "fecf5cff888bb570", - "0ee4950bd21498bd" + "78cfe60013a1bea4" ] ] }, + { + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 620, + "y": 1000, + "wires": [] + }, { "id": "ea54fcc2.cfcc2", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "get dirs", "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", "outputs": 1, @@ -3414,120 +2693,37 @@ "y": 180, "wires": [ [ - "b9a3a0f9.bcbea", - "f3662f8c7d3d7a2d" + "f3662f8c7d3d7a2d", + "01e4783e148c6698" ] ] }, { "id": "2f4c0f98.dee2", "type": "link in", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "filelist", "links": [ + "50eeb3e362f9027f", "960912e90ba5b5bc", "a4f09e25.02569", "ed35109311335099", "fb13752beddee9f2" ], "x": 355, - "y": 140, + "y": 220, "wires": [ [ "ea54fcc2.cfcc2" ] ] }, - { - "id": "b9a3a0f9.bcbea", - "type": "ui_table", - "z": "4981d84ef1a366d1", - "group": "b5fdd57b.15eda8", - "name": "", - "order": 1, - "width": 13, - "height": 7, - "columns": [ - { - "field": "Date", - "title": "Date", - "width": "150", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Name", - "title": "Name", - "width": "150", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Photos", - "title": "Photos", - "width": "80", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Duration", - "title": "ΔT", - "width": "60", - "align": "left", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Size", - "title": "Size", - "width": "80", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Status", - "title": "Status", - "width": "140", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - } - ], - "outputs": 1, - "cts": true, - "x": 610, - "y": 180, - "wires": [ - [ - "50710948.71c308", - "4082b136.dae18", - "834046a4.647938", - "0c387c0291d6c131" - ] - ] - }, { "id": "952ce286.4ffd4", "type": "ui_text", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", - "order": 3, + "order": 4, "width": 6, "height": 1, "name": "Status", @@ -3542,7 +2738,7 @@ { "id": "d4383424.7807c8", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "upload", "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", "outputs": 2, @@ -3561,7 +2757,7 @@ { "id": "50710948.71c308", "type": "change", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "set", "rules": [ { @@ -3589,9 +2785,9 @@ { "id": "834046a4.647938", "type": "ui_text", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", - "order": 4, + "order": 5, "width": 6, "height": 1, "name": "Set", @@ -3606,7 +2802,7 @@ { "id": "9a132ab1.b21658", "type": "change", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "flag.true", "rules": [ { @@ -3633,9 +2829,9 @@ { "id": "3c67e97b.9d19a6", "type": "function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "enable", - "func": "if (global.get('flag') === false){\n msg.enabled = false\n msg.color=\"white\"\n}\nelse{\n msg.enabled = true\n msg.color=\"red\"\n \n}\n\nreturn msg", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", @@ -3656,7 +2852,7 @@ { "id": "bfc01f26.c32cf", "type": "change", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "flag.false", "rules": [ { @@ -3683,7 +2879,7 @@ { "id": "b33d604c.5f1a6", "type": "link in", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "enable cloud", "links": [ "4082b136.dae18", @@ -3704,7 +2900,7 @@ { "id": "f6bd1a04.470838", "type": "change", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "set", "rules": [ { @@ -3731,7 +2927,7 @@ { "id": "4082b136.dae18", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "links": [ "b33d604c.5f1a6", @@ -3744,7 +2940,7 @@ { "id": "f20f2dbc.0f123", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "mode": "link", "links": [ @@ -3759,7 +2955,7 @@ { "id": "8689e938.dd9e38", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "mode": "link", "links": [ @@ -3774,7 +2970,7 @@ { "id": "15de0ebb.616d61", "type": "ui_toast", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "position": "dialog", "displayTime": "3", "highlight": "", @@ -3797,7 +2993,7 @@ { "id": "a7d89487.ee8858", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "del", "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", "outputs": 1, @@ -3812,16 +3008,11 @@ { "id": "a4f09e25.02569", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", + "mode": "link", "links": [ - "2f4c0f98.dee2", - "c20357dd.374108", - "e9aab326.a6896", - "edd22cc7.befe1", - "19b81967.49db87", - "8ee1b3bb.7b0b3", - "d5246b3cc796afc6" + "2f4c0f98.dee2" ], "x": 775, "y": 360, @@ -3830,7 +3021,7 @@ { "id": "7a93d1e18254685c", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "mode": "link", "links": [ @@ -3844,7 +3035,7 @@ { "id": "4d99c601c9881680", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "refresh", "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", "outputs": 2, @@ -3863,7 +3054,7 @@ { "id": "372e95797a3f2f3b", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "limit :)", "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", "outputs": 1, @@ -3878,7 +3069,7 @@ { "id": "573edbfdb7500ddc", "type": "delay", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "pauseType": "rate", "timeout": "5", @@ -3903,7 +3094,7 @@ { "id": "dacb1f078b624e10", "type": "ui_toast", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "position": "dialog", "displayTime": "3", "highlight": "", @@ -3926,7 +3117,7 @@ { "id": "92c98e6ce7cd25f9", "type": "link in", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "links": [ "7a93d1e18254685c", @@ -3943,7 +3134,7 @@ { "id": "3d16b3789632784d", "type": "ui_toast", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "position": "dialog", "displayTime": "3", "highlight": "", @@ -3964,7 +3155,7 @@ { "id": "6434e713f088012b", "type": "ui_toast", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "position": "dialog", "displayTime": "3", "highlight": "", @@ -3985,9 +3176,9 @@ { "id": "c8d65cc7c2ff7c36", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "del", - "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if os.path.isdir(dir + i):\n shutil.rmtree(dir + i)\n else:\n os.remove(dir + i)\n\nreturn msg", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", "outputs": 1, "x": 690, "y": 340, @@ -4000,7 +3191,7 @@ { "id": "f4e9a4bd79b4221f", "type": "function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "msg", "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", "outputs": 1, @@ -4019,7 +3210,7 @@ { "id": "2806bf08ea21216d", "type": "function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "msg", "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", "outputs": 1, @@ -4038,7 +3229,7 @@ { "id": "61990987acd0f263", "type": "link in", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "links": [ "6c6ef2255a7d39e5" @@ -4054,10 +3245,10 @@ { "id": "e8e488a6dd5d0b33", "type": "ui_template", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", "name": "Download", - "order": 6, + "order": 8, "width": 3, "height": 1, "format": "\n
Download\n
\n", @@ -4075,7 +3266,7 @@ { "id": "0c387c0291d6c131", "type": "function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "msg", "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", "outputs": 1, @@ -4094,10 +3285,11 @@ { "id": "e5f38b4a07a5e278", "type": "link in", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "links": [ - "960912e90ba5b5bc" + "960912e90ba5b5bc", + "50eeb3e362f9027f" ], "x": 655, "y": 220, @@ -4110,7 +3302,7 @@ { "id": "e434ef42bd6b92e8", "type": "ui_template", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", "name": "upload2", "order": 7, @@ -4126,19 +3318,18 @@ "y": 460, "wires": [ [ - "f6bd1a04.470838", - "bfc01f26.c32cf" + "f6bd1a04.470838" ] ] }, { "id": "c46e10b9c201913e", "type": "ui_template", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", "name": "refresh", - "order": 1, - "width": 3, + "order": 2, + "width": 4, "height": 1, "format": "refresh{{msg.text}}", "storeOutMessages": false, @@ -4158,10 +3349,10 @@ { "id": "d5d840183025d91b", "type": "ui_template", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", "name": "del set", - "order": 9, + "order": 11, "width": 2, "height": 1, "format": "delete set", @@ -4181,7 +3372,7 @@ { "id": "ab9e90ab5a53a0dd", "type": "ui_template", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", "name": "del ", "order": 10, @@ -4204,10 +3395,10 @@ { "id": "478994f671a3907d", "type": "ui_template", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", "name": "combine", - "order": 8, + "order": 9, "width": 2, "height": 1, "format": "combine", @@ -4227,7 +3418,7 @@ { "id": "189c1eed09624a7b", "type": "function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "combine", "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", "outputs": 1, @@ -4246,7 +3437,7 @@ { "id": "51bfd0fb7b1d292e", "type": "function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "combine", "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", "outputs": 1, @@ -4263,7 +3454,7 @@ { "id": "da325be8e74179be", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "combine", "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", "outputs": 1, @@ -4278,7 +3469,7 @@ { "id": "ed35109311335099", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "mode": "link", "links": [ @@ -4292,7 +3483,7 @@ { "id": "1493398979a63775", "type": "ui_toast", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "position": "dialog", "displayTime": "3", "highlight": "", @@ -4315,7 +3506,7 @@ { "id": "ada1b6f7cccc9344", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "combine", "mode": "link", "links": [ @@ -4328,7 +3519,7 @@ { "id": "6dd356510c446cf4", "type": "link in", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "combine", "links": [ "ada1b6f7cccc9344" @@ -4344,11 +3535,12 @@ { "id": "b42e061fb1f1f3d7", "type": "link out", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "mode": "link", "links": [ - "397ab7f44b893c89" + "397ab7f44b893c89", + "3876d5cbd248592b" ], "x": 435, "y": 140, @@ -4357,7 +3549,7 @@ { "id": "b99505440832439f", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "diskspace", "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", "outputs": 1, @@ -4372,7 +3564,7 @@ { "id": "92047434f8e9f927", "type": "ui_toast", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "position": "dialog", "displayTime": "3", "highlight": "", @@ -4393,7 +3585,7 @@ { "id": "f3662f8c7d3d7a2d", "type": "delay", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "", "pauseType": "rate", "timeout": "5", @@ -4418,7 +3610,7 @@ { "id": "51579603bce21e98", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "read", "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", "outputs": 1, @@ -4433,10 +3625,10 @@ { "id": "9a5baae623355f9d", "type": "ui_template", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "db43d646.2074c8", "name": "preview", - "order": 5, + "order": 6, "width": 6, "height": 6, "format": "
\n\n\n
\n", @@ -4454,7 +3646,7 @@ { "id": "85839a17fb7b58b9", "type": "python3-function", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "name": "preview", "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", "outputs": 1, @@ -4467,40 +3659,97 @@ ] }, { - "id": "45058bfcf047e8cc", - "type": "inject", - "z": "4981d84ef1a366d1", + "id": "01e4783e148c6698", + "type": "ui_table", + "z": "80a3942785a26c29", + "group": "b5fdd57b.15eda8", "name": "", - "props": [ + "order": 1, + "width": 13, + "height": 7, + "columns": [ + { + "field": "Date", + "title": "Date", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Name", + "title": "Name", + "width": "150", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Photos", + "title": "Photos", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, { - "p": "payload" + "field": "Duration", + "title": "ΔT", + "width": "60", + "align": "left", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } }, { - "p": "topic", - "vt": "str" + "field": "Size", + "title": "Size", + "width": "80", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } + }, + { + "field": "Status", + "title": "Status", + "width": "140", + "align": "center", + "formatter": "plaintext", + "formatterParams": { + "target": "_blank" + } } ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "", - "payloadType": "date", - "x": 100, - "y": 120, + "outputs": 1, + "cts": true, + "x": 610, + "y": 180, "wires": [ - [] + [ + "4082b136.dae18", + "50710948.71c308", + "834046a4.647938", + "0c387c0291d6c131" + ] ] }, { - "id": "40dee936a9abac0d", + "id": "cb3437ec113e1b6f", "type": "ui_switch", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "label": "SSH", "tooltip": "", - "group": "4fe6b4c0ade0938a", + "group": "4390b2ebcbbe104c", "order": 3, "width": 6, "height": 1, @@ -4520,21 +3769,21 @@ "animate": false, "className": "", "x": 390, - "y": 340, + "y": 360, "wires": [ [ - "dc354c54078ca607" + "c24f61b87e3226dd" ] ] }, { - "id": "4fd9bb53fdb51a25", + "id": "60fd0adce1cfeb82", "type": "ui_switch", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "label": "Samba", "tooltip": "", - "group": "4fe6b4c0ade0938a", + "group": "4390b2ebcbbe104c", "order": 4, "width": 6, "height": 1, @@ -4554,32 +3803,32 @@ "animate": false, "className": "", "x": 400, - "y": 380, + "y": 400, "wires": [ [ - "b0aa8ffae5a3578a" + "441d3ef525e901da" ] ] }, { - "id": "dc354c54078ca607", + "id": "c24f61b87e3226dd", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "ssh", "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", "outputs": 1, "x": 530, - "y": 340, + "y": 360, "wires": [ [] ] }, { - "id": "52858b4eceacc902", + "id": "c013e836e759a085", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", - "group": "4fe6b4c0ade0938a", + "group": "4390b2ebcbbe104c", "order": 2, "width": 6, "height": 1, @@ -4595,45 +3844,17 @@ "topic": "topic", "topicType": "msg", "x": 120, - "y": 300, - "wires": [ - [ - "f99ec8781a33ec7d" - ] - ] - }, - { - "id": "595153429adef33b", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Wifi", - "group": "0fe66c9190b8a87c", - "order": 1, - "width": 6, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Network Settings

Hostname

The device can be accessed through any browser in the same network. Therefore, you can either enter the device's IP address or the given hostname. The standard name is 'openscan' but it is highly recommended to change the name, when using multiple devices (e.g. 'openscan1', 'openscan2' ...)

Select Wifi

After booting, the device will automatically search for available wireless networks and create a list. You can connect to a given network by entering the wifi password and country code. To find the right two-character country code, see the following list: ISO 3166 Country Code on Wikipedia

Search Wifi

You can manually refresh the list of available networks by pressing this button.

Reset Wifi

Delete the list of known wireless networks (and passwords) and reset the default. After this step, you will either need to use Ethernet or a modified wpa_supplicant.conf file. (see glennklockwood.com for more details about the wpa_supplicant.conf file, which has to be manually created and placed into the /boot/ directory of the sd-card)

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 590, - "y": 120, + "y": 320, "wires": [ [ - "f304680180a23479" + "b78346ca3ce70c68" ] ] }, { - "id": "7dc39bd847d16ded", + "id": "f0d8dbcca76a1926", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -4646,19 +3867,19 @@ "topic": "", "name": "", "x": 410, - "y": 300, + "y": 320, "wires": [ [ - "5f849178998d9082" + "e95b86cbac1b03b9" ] ] }, { - "id": "02858034e17b827f", + "id": "34374044c0030625", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "General", - "group": "4fe6b4c0ade0938a", + "group": "4390b2ebcbbe104c", "order": 1, "width": 6, "height": 1, @@ -4674,19 +3895,19 @@ "topic": "topic", "topicType": "msg", "x": 740, - "y": 240, + "y": 220, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "675d4933a44ae6b5", + "id": "b2b6bf23c9989133", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Pinout", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 1, "width": 6, "height": 1, @@ -4702,219 +3923,32 @@ "topic": "topic", "topicType": "msg", "x": 430, - "y": 200, + "y": 220, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "b0aa8ffae5a3578a", + "id": "441d3ef525e901da", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "smb", "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", "outputs": 1, "x": 530, - "y": 380, - "wires": [ - [] - ] - }, - { - "id": "cc3cb10f2ea3f8b8", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "blink Light1", - "func": "import RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nfrom OpenScan import ringlight\nfrom time import sleep\n\ndelay = 0.1\nringlight(2,False)\n\nfor i in range (5):\n ringlight(1,True)\n sleep(delay)\n ringlight(1,False)\n sleep(delay)", - "outputs": 1, - "x": 290, - "y": 760, - "wires": [ - [] - ] - }, - { - "id": "d114f4d4d7f31981", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "reboot", - "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", - "outputs": 1, - "x": 270, - "y": 720, + "y": 400, "wires": [ [] ] }, { - "id": "79181ad3b56d5c62", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "4fe6b4c0ade0938a", - "order": 7, - "width": 2, - "height": 1, - "name": "", - "label": "Model", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 730, - "y": 620, - "wires": [] - }, - { - "id": "4d81bd138733c410", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "4fe6b4c0ade0938a", - "order": 9, - "width": 2, - "height": 1, - "name": "", - "label": "Camera", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 840, - "y": 420, - "wires": [] - }, - { - "id": "80b579a4220e5c23", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "model", - "label": "", - "tooltip": "", - "place": "Select option", - "group": "4fe6b4c0ade0938a", - "order": 8, - "width": 4, - "height": 1, - "passthru": true, - "multiple": false, - "options": [ - { - "label": "Please Select", - "value": "None", - "type": "str" - }, - { - "label": "OpenScan Mini", - "value": "OSMini", - "type": "str" - }, - { - "label": "OpenScan Classic", - "value": "OSClassic", - "type": "str" - } - ], - "payload": "", - "topic": "topic", - "topicType": "msg", - "className": "", - "x": 390, - "y": 620, - "wires": [ - [ - "896242c5a7e50fa7" - ] - ] - }, - { - "id": "a2c1dba3e67be015", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "Camera", - "label": "", - "tooltip": "", - "place": "Select option", - "group": "4fe6b4c0ade0938a", - "order": 10, - "width": 4, - "height": 1, - "passthru": true, - "multiple": false, - "options": [ - { - "label": "Pi Cam v1 - 5mp", - "value": "ov5647", - "type": "str" - }, - { - "label": "Pi Cam v2 - 8mp", - "value": "imx219", - "type": "str" - }, - { - "label": "Pi Cam HQ - 12.3mp", - "value": "imx477", - "type": "str" - }, - { - "label": "Arducam IMX519 - 16mp", - "value": "imx519", - "type": "str" - }, - { - "label": "IMX290 a", - "value": "imx290a", - "type": "str" - }, - { - "label": "IMX290 b", - "value": "imx290b", - "type": "str" - }, - { - "label": "IMX378", - "value": "imx378", - "type": "str" - }, - { - "label": "OV9281", - "value": "ov9281", - "type": "str" - }, - { - "label": "DSLR (gphoto)", - "value": "gphoto", - "type": "str" - }, - { - "label": "USB Webcam", - "value": "usb_webcam", - "type": "str" - }, - { - "label": "External Camera", - "value": "external", - "type": "str" - } - ], - "payload": "", - "topic": "topic", - "topicType": "msg", - "className": "", - "x": 400, - "y": 420, - "wires": [ - [ - "4058a31e942e8f95", - "6d68cccec646e0a0" - ] - ] - }, - { - "id": "9cf5d56263caada7", + "id": "3256bab150113a48", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Motor", - "group": "d49a6dfd7fb17096", + "group": "7a3279eea439bcdd", "order": 1, "width": 6, "height": 1, @@ -4930,19 +3964,19 @@ "topic": "topic", "topicType": "msg", "x": 430, - "y": 120, + "y": 140, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "72238e6a01d1152c", + "id": "7a186669a17daa71", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "camera", - "group": "93aadb71dee6d977", + "group": "d324f0b852c2df0a", "order": 1, "width": 6, "height": 1, @@ -4958,71 +3992,41 @@ "topic": "topic", "topicType": "msg", "x": 420, - "y": 160, + "y": 180, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "15a0a2f431ce55c3", + "id": "edac7dd292e7e486", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "General Settings", "info": "", "x": 120, - "y": 260, - "wires": [] - }, - { - "id": "87a403b9a09aa38d", - "type": "comment", - "z": "017bd4e4a428bee5", - "name": "Network", - "info": "", - "x": 100, - "y": 880, + "y": 280, "wires": [] }, { - "id": "896242c5a7e50fa7", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "model", - "func": "from OpenScan import load_str, save\n\nstate = msg['payload']\nmsg['state'] = state\n\nif state != load_str('model'):\n save('model', state)\n if state == 'OSMini':\n save('rotor_stepsperrotation',48000)\n save('cam_rotation',90)\n save('rotor_anglemin',-70)\n save('rotor_anglemax',20)\n \n\n if state == 'OSClassic':\n save('rotor_stepsperrotation',17067)\n save('cam_rotation',0)\n save('rotor_anglemin',-30)\n save('rotor_anglemax',30)\n\nif state == \"OSMini\":\n msg['crop2'] = 'Crop X (%)'\n msg['crop1'] = 'Crop Y (%)'\nelif state == \"OSClassic\":\n msg['crop1'] = 'Crop X (%)'\n msg['crop2'] = 'Crop Y (%)'\n\nreturn msg", - "outputs": 1, - "x": 530, - "y": 620, - "wires": [ - [ - "f358de1e64b491bb" - ] - ] - }, - { - "id": "4058a31e942e8f95", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "camera", - "func": "from OpenScan import load_str, save\nfrom json import load\nstate = msg['payload']\nstate_old = load_str('camera')\n\nif state_old != state:\n save('camera',state)\n return msg", - "outputs": 1, - "x": 540, - "y": 500, - "wires": [ - [ - "34b685aff2080d31" - ] - ] - }, - { - "id": "c833f6243a059d83", + "id": "161b52034e578ee2", + "type": "comment", + "z": "e43a27722b508115", + "name": "Network", + "info": "", + "x": 100, + "y": 720, + "wires": [] + }, + { + "id": "f6d6cc35679ede63", "type": "ui_switch", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "more sets", "label": "Advanced Settings", "tooltip": "", - "group": "4fe6b4c0ade0938a", + "group": "4390b2ebcbbe104c", "order": 5, "width": 6, "height": 1, @@ -5042,71 +4046,47 @@ "animate": false, "className": "", "x": 400, - "y": 660, + "y": 480, "wires": [ [ - "8be8015931c663cc" + "f06a7bcad524e9f9" ] ] }, { - "id": "15fd1c9e5610cb85", + "id": "29745a36fc157f3f", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "more sets", "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", "outputs": 2, "x": 820, - "y": 660, - "wires": [ - [ - "62cd775a1c02dac8" - ], - [ - "c833f6243a059d83" - ] - ] - }, - { - "id": "74c5c7cd2681045b", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "load camera&model", - "func": "from OpenScan import load_str, load_bool\n\nmodel = load_str('model')\ncamera = load_str('camera')\nupdate = load_bool('updateable')\nmsg['model'] = model\nmsg['camera'] = camera\nmsg2 = {}\nmsg3 = {}\nmsg4 = {}\n\nif camera in ('imx219','ov5647','imx477','imx290a','imx290b','imx378','ov9281','gphoto'):\n msg['payload'] = {\"group\":{\"hide\":[\"Scan_Arducam\"],\"show\":[\"Scan_Settings\",\"Scan_Picamera\"]}}\nelif camera in ('imx519'):\n msg['payload'] = {\"group\":{\"hide\":[\"Scan_Picamera\"],\"show\":[\"Scan_Settings\",\"Scan_Arducam\"]}}\nelif camera in ('external'):\n msg['payload'] = {\"group\":{\"hide\":[\"Scan_Arducam\",\"Scan_Picamera\"],\"show\":[\"Scan_Settings\"]}}\n\n\nif model == 'None' or model == '' or camera == 'None' or camera == '':\n msg2['payload']={\"tabs\": {\"hide\": [\"Scan\", \"Files&Cloud\",\"Settings\",\"Update & Info\"]}}\n msg3['payload'] = {\"group\":{\"hide\":[\"OpenScan_Home\"],\"show\":[\"OpenScan_Initialize\"]}}\nelse:\n msg2['payload']={\"tabs\": {\"show\": [\"Scan\", \"Files&Cloud\",\"Settings\",\"Update & Info\"]},\"hide\":{}}\n msg3['payload'] = {\"group\":{\"show\":[\"OpenScan_Home\"],\"hide\":[\"OpenScan_Initialize\"]}}\n\nif update == True:\n msg4['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg4['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\nreturn msg,msg2,msg3,msg4", - "outputs": 4, - "x": 340, - "y": 40, + "y": 480, "wires": [ [ - "b4db790aad28ba39" - ], - [ - "b4db790aad28ba39" - ], - [ - "b4db790aad28ba39" + "8750ad979e9ea246" ], [ - "b4db790aad28ba39" + "f6d6cc35679ede63" ] ] }, { - "id": "b4db790aad28ba39", + "id": "bf23328f9fb11b22", "type": "ui_ui_control", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "change visibility", "events": "all", "x": 600, - "y": 40, + "y": 60, "wires": [ [] ] }, { - "id": "eb8ccf2786ea3d63", + "id": "b37be1d222bc70c9", "type": "inject", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "1s_repeater", "props": [ { @@ -5125,60 +4105,62 @@ "payload": "", "payloadType": "date", "x": 150, - "y": 40, + "y": 60, "wires": [ [ - "74c5c7cd2681045b", - "9b756a1f9b0e7317" + "89eedf29b404f750" ] ] }, { - "id": "9b756a1f9b0e7317", + "id": "89eedf29b404f750", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "load advanced", - "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\nreturn msg", - "outputs": 1, - "x": 320, - "y": 80, + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, "wires": [ [ - "b4db790aad28ba39" + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" ] ] }, { - "id": "ca4afadb5b21751f", + "id": "2050de5d9e02f69f", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Info Texts", "info": "", "x": 100, - "y": 120, + "y": 140, "wires": [] }, { - "id": "f393400.d87dcc", + "id": "ded3086945a6d4b5", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "check ip address", "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", "outputs": 1, - "x": 410, - "y": 1060, + "x": 250, + "y": 940, "wires": [ [ - "bb789eed.9f73c" + "3cfe464506f46ecd" ] ] }, { - "id": "bb789eed.9f73c", + "id": "3cfe464506f46ecd", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "0fe66c9190b8a87c", - "order": 2, + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, "width": 0, "height": 0, "name": "", @@ -5186,299 +4168,26 @@ "format": "{{msg.ip}}", "layout": "row-spread", "className": "", - "x": 590, - "y": 1060, + "x": 430, + "y": 940, "wires": [] }, { - "id": "2a0f9919.4c9a86", + "id": "bd206ad109831e6a", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "OpenScanCloud", "info": "", "x": 120, - "y": 1240, + "y": 1260, "wires": [] }, { - "id": "27c6b221c90ed9e1", - "type": "exec", - "z": "017bd4e4a428bee5", - "command": "iwlist wlan0 scan | grep ESSID | sed 's/ESSID://g;s/\"//g;s/^ *//;s/ *$//'", - "addpay": false, - "append": "", - "useSpawn": "false", - "timer": "", - "winHide": false, - "oldrc": false, - "name": "scan", - "x": 250, - "y": 1040, - "wires": [ - [ - "b05cf92302a5c112", - "f393400.d87dcc" - ], - [ - "e9677b85856b5873" - ], - [] - ] - }, - { - "id": "b05cf92302a5c112", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "WIFI", - "func": "msg['options']=[]\n\nfor i in msg['payload'].split('\\n'):\n if i not in msg['options'] and i!=\"\":\n msg['options'].append(i)\n \nif len(msg['options']) != 0:\n msg['enabled']=True\n\nreturn msg", - "outputs": 1, - "x": 370, - "y": 1020, - "wires": [ - [ - "59c9f67283ba1709" - ] - ] - }, - { - "id": "da5ddaf4cc25b8c8", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "search", - "group": "0fe66c9190b8a87c", - "order": 4, - "width": 3, - "height": 1, - "passthru": false, - "label": "Search Wifi", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "true", - "payloadType": "bool", - "topic": "", - "topicType": "str", - "x": 90, - "y": 980, - "wires": [ - [ - "27c6b221c90ed9e1", - "51521bc6eb44cde5" - ] - ] - }, - { - "id": "59c9f67283ba1709", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "", - "label": "", - "tooltip": "", - "place": "Select Wifi", - "group": "0fe66c9190b8a87c", - "order": 3, - "width": 6, - "height": 1, - "passthru": true, - "multiple": false, - "options": [], - "payload": "", - "topic": "", - "topicType": "str", - "className": "", - "x": 520, - "y": 980, - "wires": [ - [ - "2bb52656f9554dab" - ] - ] - }, - { - "id": "b2d7d6a730f7dca6", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Reset Wifi", - "group": "0fe66c9190b8a87c", - "order": 5, - "width": 3, - "height": 1, - "passthru": false, - "label": "Reset Wifi", - "tooltip": "", - "color": "red", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "Delete all prior wifi connections? (You will need to reconnect to the OpenScan device by Ethernet or manually modify the wpa_supplicant.conf)", - "payloadType": "str", - "topic": "", - "topicType": "str", - "x": 110, - "y": 1140, - "wires": [ - [ - "78985ac6d3bcdf60" - ] - ] - }, - { - "id": "c3b8faac9ebb2c80", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "Reset Wifi", - "func": "from time import sleep\n\nif msg['payload']!=\"Yes\":\n return\n\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\nsleep(3)\nos.system('systemctl restart nodered')\nreturn msg", - "outputs": 1, - "x": 440, - "y": 1140, - "wires": [ - [] - ] - }, - { - "id": "78985ac6d3bcdf60", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 270, - "y": 1140, - "wires": [ - [ - "c3b8faac9ebb2c80" - ] - ] - }, - { - "id": "4f7f49b12c2d2572", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "add Wifi", - "func": "from time import sleep\nsleep(0.1)\n\nos.system('wpa_cli -i wlan0 reconfigure')\n\nreturn msg", - "outputs": 1, - "x": 1320, - "y": 1000, - "wires": [ - [] - ] - }, - { - "id": "ebcc98685059b9d4", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "password", - "x": 780, - "y": 980, - "wires": [ - [ - "68204a14528ab842" - ] - ] - }, - { - "id": "68204a14528ab842", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "if msg['payload'] == 'Cancel':\n return\n\nmsg['password'] = msg['payload']\nmsg['payload']='Enter country code (ISO 3166-1 alpha-2, see: Wikipedia)'\n\n\nreturn msg", - "outputs": 1, - "x": 910, - "y": 980, - "wires": [ - [ - "852edf901bdec9c5" - ] - ] - }, - { - "id": "852edf901bdec9c5", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "Save", - "cancel": "Cancel", - "raw": true, - "className": "", - "topic": "", - "name": "country", - "x": 1040, - "y": 980, - "wires": [ - [ - "1b09d634e3d9357b" - ] - ] - }, - { - "id": "1b09d634e3d9357b", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "modWPA", - "func": "if msg['payload'] == 'Cancel':\n return\n\nif len(msg['payload'])!=2:\n msg['payload'] = 'invalid country code'\n return msg,None\n\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\ntemp_dir = '/home/pi/OpenScan/tmp/wpa'\n\ncode = msg['payload'].upper()\nssid = msg['ssid']\npassword = msg['password']\n\nif len(code) != 2:\n msg['topic'] = 'ERROR'\n msg['payload'] = 'invalid country code (see ISO 3166-1 alpha-2)'\n return msg\n\nwith open(wpa_dir, 'r') as file:\n for i in file.readlines():\n if 'country=' in i:\n code_old=i.split('country=')[1][0:2]\n break\n\nwith open(wpa_dir, 'r') as file:\n wpa = file.read()\n if ssid in wpa:\n msg['topic'] = 'ERROR'\n msg['payload'] = 'Network already exists! If you have trouble connecting, please consider resetting the saved Wifi connections.'\n return msg\n wpa=wpa.replace('country=' + code_old, 'country=' + code)\n wpa=wpa + '\\nnetwork={\\n priority=10\\n ssid=\"'+ssid+'\"\\n psk=\"'+password+'\"\\n}\\n'\n\nwith open(temp_dir,'w+') as file:\n file.write(wpa)\nos.system('mv '+temp_dir + ' ' + wpa_dir)\n\nmsg['topic'] = 'Updating Wifi'\nmsg['payload'] = 'reconnecting might take a moment'\nreturn msg,msg\n", - "outputs": 2, - "x": 1180, - "y": 980, - "wires": [ - [ - "03732a7d3b0c95aa" - ], - [ - "4f7f49b12c2d2572" - ] - ] - }, - { - "id": "03732a7d3b0c95aa", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 1330, - "y": 960, - "wires": [ - [] - ] - }, - { - "id": "e97d17c6590138e2", + "id": "b70a9a665c1e4d36", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Cloud-settings", - "group": "3b4bd36726be16d5", + "group": "12b719cba49817c9", "order": 1, "width": 6, "height": 1, @@ -5493,19 +4202,19 @@ "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 620, - "y": 160, + "x": 740, + "y": 260, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "f7bf47e3eec6d736", + "id": "c9f0566601a3e130", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", "order": 4, "width": 0, "height": 0, @@ -5515,14 +4224,14 @@ "layout": "row-spread", "className": "", "x": 410, - "y": 1380, + "y": 1400, "wires": [] }, { - "id": "b52d91c628b151a4", + "id": "9bd86d27ea499a2a", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", "order": 5, "width": 0, "height": 0, @@ -5532,14 +4241,14 @@ "layout": "row-spread", "className": "", "x": 390, - "y": 1420, + "y": 1440, "wires": [] }, { - "id": "1969c709ef2fd1d5", + "id": "2c37f7030810d234", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", "order": 3, "width": 0, "height": 0, @@ -5549,32 +4258,32 @@ "layout": "row-spread", "className": "", "x": 370, - "y": 1460, + "y": 1480, "wires": [] }, { - "id": "88e92b621d2a3394", + "id": "f40286c18afd4501", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "save", "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", "outputs": 2, "x": 750, - "y": 1320, + "y": 1340, "wires": [ [ - "76acd48a511a5e3e", - "b01581296b94dfcd" + "455a5266017ea121", + "50f73cee213ec05c" ], [ - "9c51aa678f16980f" + "264eece408043021" ] ] }, { - "id": "76acd48a511a5e3e", + "id": "455a5266017ea121", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -5586,19 +4295,19 @@ "topic": "", "name": "", "x": 890, - "y": 1280, + "y": 1300, "wires": [ [] ] }, { - "id": "5f50ed3f6ba37cef", + "id": "c368df68593bc2bf", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "label": "Token", "tooltip": "", - "group": "3b4bd36726be16d5", + "group": "12b719cba49817c9", "order": 2, "width": 6, "height": 1, @@ -5610,68 +4319,69 @@ "className": "", "topicType": "str", "x": 350, - "y": 1340, + "y": 1360, "wires": [ [ - "cb62d30728af2968" + "18fd1afa768187b3" ] ] }, { - "id": "cb62d30728af2968", + "id": "18fd1afa768187b3", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Save?", "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", "outputs": 2, "x": 470, - "y": 1340, + "y": 1360, "wires": [ [ - "94e503dd2e64d903" + "418aea2ec65573a0" ], [ - "d859bb39914d4999" + "9792c89c5f4429f9" ] ] }, { - "id": "0dd01eef6e70059e", + "id": "f90a98899b7a71d0", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "text", "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", "outputs": 1, "x": 230, - "y": 1340, + "y": 1360, "wires": [ [ - "5f50ed3f6ba37cef" + "c368df68593bc2bf" ] ] }, { - "id": "788fabff98c7973c", + "id": "b4c843620c251c43", "type": "link in", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "token", "links": [ "960912e90ba5b5bc", - "b01581296b94dfcd", - "d859bb39914d4999" + "50f73cee213ec05c", + "9792c89c5f4429f9", + "50eeb3e362f9027f" ], "x": 75, - "y": 1340, + "y": 1360, "wires": [ [ - "0dd01eef6e70059e" + "f90a98899b7a71d0" ] ] }, { - "id": "94e503dd2e64d903", + "id": "418aea2ec65573a0", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -5684,74 +4394,75 @@ "topic": "", "name": "", "x": 610, - "y": 1320, + "y": 1340, "wires": [ [ - "88e92b621d2a3394" + "f40286c18afd4501" ] ] }, { - "id": "d859bb39914d4999", + "id": "9792c89c5f4429f9", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "mode": "link", "links": [ - "788fabff98c7973c" + "b4c843620c251c43" ], "x": 555, - "y": 1360, + "y": 1380, "wires": [] }, { - "id": "9c51aa678f16980f", + "id": "264eece408043021", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "links": [ "5d267acc10020091", - "397ab7f44b893c89" + "3876d5cbd248592b" ], "x": 835, - "y": 1360, + "y": 1380, "wires": [] }, { - "id": "397ab7f44b893c89", + "id": "3876d5cbd248592b", "type": "link in", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "OSCparameters", "links": [ "960912e90ba5b5bc", - "9c51aa678f16980f", - "b42e061fb1f1f3d7" + "264eece408043021", + "b42e061fb1f1f3d7", + "50eeb3e362f9027f" ], "x": 75, - "y": 1380, + "y": 1400, "wires": [ [ - "a7fd00943edc380b" + "5daca3ec47f8e7fc" ] ] }, { - "id": "b01581296b94dfcd", + "id": "50f73cee213ec05c", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "links": [ - "788fabff98c7973c", + "b4c843620c251c43", "5d267acc10020091" ], "x": 835, - "y": 1320, + "y": 1340, "wires": [] }, { - "id": "bf6d941ad307ce22", + "id": "95578e54a9b61cba", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "prompt", "displayTime": "3", "highlight": "", @@ -5764,35 +4475,35 @@ "topic": "", "name": "", "x": 250, - "y": 1520, + "y": 1540, "wires": [ [ - "f22dfef37d5de773" + "d7a5693da7855da8" ] ] }, { - "id": "f22dfef37d5de773", + "id": "d7a5693da7855da8", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", "outputs": 2, "x": 390, - "y": 1520, + "y": 1540, "wires": [ [ - "54602ee49ca022e7" + "2b02b97dd1614e52" ], [ - "1505f3e72f971081" + "183a629accb417b1" ] ] }, { - "id": "1505f3e72f971081", + "id": "183a629accb417b1", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -5805,15 +4516,15 @@ "topic": "", "name": "", "x": 530, - "y": 1560, + "y": 1580, "wires": [ [] ] }, { - "id": "54602ee49ca022e7", + "id": "2b02b97dd1614e52", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "prompt", "displayTime": "3", "highlight": "", @@ -5826,17 +4537,17 @@ "topic": "", "name": "", "x": 530, - "y": 1520, + "y": 1540, "wires": [ [ - "f9efcb87b74abbd4" + "3e4c15d7b538f816" ] ] }, { - "id": "510dbe4d76253bd6", + "id": "3bf622f344172721", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "prompt", "displayTime": "3", "highlight": "", @@ -5849,35 +4560,35 @@ "topic": "", "name": "", "x": 810, - "y": 1520, + "y": 1540, "wires": [ [ - "600b2306caed1640" + "e431cb2b8d217cee" ] ] }, { - "id": "600b2306caed1640", + "id": "e431cb2b8d217cee", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", "outputs": 1, "x": 950, - "y": 1520, + "y": 1540, "wires": [ [ - "bbad1ab5f8f63fb7" + "106874534890f229" ] ] }, { - "id": "d34cd203725bac15", + "id": "a38d7fde5c73210f", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Register", - "group": "3b4bd36726be16d5", - "order": 7, + "group": "12b719cba49817c9", + "order": 6, "width": 2, "height": 1, "passthru": false, @@ -5892,17 +4603,17 @@ "topic": "Requesting an OpenScanCloud Token", "topicType": "str", "x": 100, - "y": 1520, + "y": 1540, "wires": [ [ - "bf6d941ad307ce22" + "95578e54a9b61cba" ] ] }, { - "id": "bbad1ab5f8f63fb7", + "id": "106874534890f229", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -5915,67 +4626,67 @@ "topic": "", "name": "", "x": 1090, - "y": 1520, + "y": 1540, "wires": [ [] ] }, { - "id": "a7fd00943edc380b", + "id": "5daca3ec47f8e7fc", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", "outputs": 1, "x": 230, - "y": 1380, + "y": 1400, "wires": [ [ - "f7bf47e3eec6d736", - "b52d91c628b151a4", - "1969c709ef2fd1d5" + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" ] ] }, { - "id": "124459147143ec6a", + "id": "f34de19d4cf810a9", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Motor", "info": "", "x": 90, - "y": 1600, + "y": 1740, "wires": [] }, { - "id": "dbd62b91a6c9c412", + "id": "26c2b58e21f97475", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Camera", "info": "", "x": 90, - "y": 2240, + "y": 2500, "wires": [] }, { - "id": "842b6fe016087ce3", + "id": "a8ec972bad47a9a8", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Pinout", "info": "", - "x": 110, - "y": 2860, + "x": 90, + "y": 2960, "wires": [] }, { - "id": "8c1a92f2dcc976c7", + "id": "b03e8b51187e88eb", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Rotor_delay (ms)", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 14, + "group": "7a3279eea439bcdd", + "order": 16, "width": 3, "height": 1, "passthru": false, @@ -5987,22 +4698,22 @@ "step": "0.005", "className": "", "x": 450, - "y": 1840, + "y": 2100, "wires": [ [ - "bb54bbdae6690576" + "11fd3363416433f9" ] ] }, { - "id": "2647111c06f2055d", + "id": "6aae9d4fddf08cc0", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt delay", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 27, + "group": "7a3279eea439bcdd", + "order": 30, "width": 3, "height": 1, "passthru": false, @@ -6014,22 +4725,22 @@ "step": "0.005", "className": "", "x": 420, - "y": 2080, + "y": 2340, "wires": [ [ - "fb8145a9f8d4f7b2" + "e50492d1e18f43c6" ] ] }, { - "id": "f9b51424edb0491c", + "id": "543e1690693acbeb", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_acc", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 16, + "group": "7a3279eea439bcdd", + "order": 18, "width": 3, "height": 1, "passthru": false, @@ -6041,22 +4752,22 @@ "step": "0.1", "className": "", "x": 420, - "y": 1880, + "y": 2140, "wires": [ [ - "ea87ecfd2af3cc7f" + "e8b24efb0f30288e" ] ] }, { - "id": "1ab34b0a78b2c577", + "id": "9a56c087d941f1da", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_accramp", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 18, + "group": "7a3279eea439bcdd", + "order": 20, "width": 3, "height": 1, "passthru": false, @@ -6068,22 +4779,22 @@ "step": "100", "className": "", "x": 440, - "y": 1920, + "y": 2180, "wires": [ [ - "249f44c3a87793ba" + "29f576be9e292232" ] ] }, { - "id": "1d4230b3d9b93f63", + "id": "dfdebe10dbf0e198", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_stepsperrotation", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 12, + "group": "7a3279eea439bcdd", + "order": 14, "width": 3, "height": 1, "passthru": false, @@ -6094,19 +4805,19 @@ "className": "", "topicType": "msg", "x": 460, - "y": 1800, + "y": 2060, "wires": [ [ - "0bb56b1edb12c2cf" + "78e256083f59f66f" ] ] }, { - "id": "2e3222f0aba88040", + "id": "af8dfe78cbd0c301", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 17, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, "width": 3, "height": 1, "name": "rotor Accramp", @@ -6115,15 +4826,15 @@ "layout": "row-left", "className": "", "x": 780, - "y": 1880, + "y": 2140, "wires": [] }, { - "id": "9d50311679acf215", + "id": "ee4b8908a5b83880", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 11, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, "width": 3, "height": 1, "name": "rotor_Steps per Rotation", @@ -6132,15 +4843,15 @@ "layout": "row-spread", "className": "", "x": 810, - "y": 1920, + "y": 2180, "wires": [] }, { - "id": "25d7b4dd2aab8f05", + "id": "c4deaa38c1b0adbf", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 15, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, "width": 3, "height": 1, "name": "rotor Acc", @@ -6149,15 +4860,15 @@ "layout": "row-left", "className": "", "x": 760, - "y": 1840, + "y": 2100, "wires": [] }, { - "id": "15682cca9622831f", + "id": "baec873a95fff48a", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 13, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, "width": 3, "height": 1, "name": "rotor_delay", @@ -6166,15 +4877,15 @@ "layout": "row-left", "className": "", "x": 770, - "y": 1800, + "y": 2060, "wires": [] }, { - "id": "8e2d22042bfcb4e8", + "id": "355e89ab4e5484e4", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 23, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 26, "width": 6, "height": 1, "name": "tt", @@ -6183,18 +4894,18 @@ "layout": "row-center", "className": "", "x": 90, - "y": 2040, + "y": 2300, "wires": [] }, { - "id": "56bc3b93af2ebe16", + "id": "10687d331a732790", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_acc", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 29, + "group": "7a3279eea439bcdd", + "order": 32, "width": 3, "height": 1, "passthru": false, @@ -6206,22 +4917,22 @@ "step": "0.1", "className": "", "x": 410, - "y": 2120, + "y": 2380, "wires": [ [ - "35422077b53da9bf" + "af88b9da72917d62" ] ] }, { - "id": "6ef996f8a36f94c2", + "id": "721b9680a3fa460e", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_accramp", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 31, + "group": "7a3279eea439bcdd", + "order": 34, "width": 3, "height": 1, "passthru": false, @@ -6233,22 +4944,22 @@ "step": "1", "className": "", "x": 430, - "y": 2160, + "y": 2420, "wires": [ [ - "2c000bd53cdb98ca" + "b1b4678827d3a6dd" ] ] }, { - "id": "0c50fdbb5ac3c373", + "id": "c6642c7470d3820c", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_stepsperrotation", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 25, + "group": "7a3279eea439bcdd", + "order": 28, "width": 3, "height": 1, "passthru": false, @@ -6259,19 +4970,19 @@ "className": "", "topicType": "msg", "x": 450, - "y": 2040, + "y": 2300, "wires": [ [ - "485a4bed5a6bea23" + "eef89545ec0f6aa8" ] ] }, { - "id": "213ccfb441a42890", + "id": "18e5918748660109", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 30, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 33, "width": 3, "height": 1, "name": "ttAccramp", @@ -6280,15 +4991,15 @@ "layout": "row-left", "className": "", "x": 760, - "y": 2160, + "y": 2420, "wires": [] }, { - "id": "73c9b4d09dc25e54", + "id": "8e805244dc1899e8", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 24, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 27, "width": 3, "height": 1, "name": "tt_steps per Rotation", @@ -6297,15 +5008,15 @@ "layout": "row-spread", "className": "", "x": 800, - "y": 2040, + "y": 2300, "wires": [] }, { - "id": "a81824c92f22487d", + "id": "a09e5fbea861bfb1", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 28, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 31, "width": 3, "height": 1, "name": "tt Acc", @@ -6314,15 +5025,15 @@ "layout": "row-left", "className": "", "x": 750, - "y": 2120, + "y": 2380, "wires": [] }, { - "id": "9715161858f69649", + "id": "7b06448b3b222011", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 26, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 29, "width": 3, "height": 1, "name": "tt_delay", @@ -6331,18 +5042,18 @@ "layout": "row-left", "className": "", "x": 760, - "y": 2080, + "y": 2340, "wires": [] }, { - "id": "1b3ac50d2c6600c6", + "id": "0dfc86d90258f9bb", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_angle", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 20, + "group": "7a3279eea439bcdd", + "order": 22, "width": 3, "height": 1, "passthru": false, @@ -6354,19 +5065,19 @@ "step": "1", "className": "", "x": 430, - "y": 1960, + "y": 2220, "wires": [ [ - "e0d7c36daa42b3f3" + "c4b5a38c5c1df3d2" ] ] }, { - "id": "6dcd1f0ccb01a299", + "id": "9319d7d4f34c6d22", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 19, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, "width": 3, "height": 1, "name": "rotor_angle", @@ -6375,18 +5086,18 @@ "layout": "row-spread", "className": "", "x": 770, - "y": 1960, + "y": 2220, "wires": [] }, { - "id": "16e9a3a71c4bb916", + "id": "1610895f430b9aca", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_angle", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 33, + "group": "7a3279eea439bcdd", + "order": 36, "width": 3, "height": 1, "passthru": false, @@ -6398,19 +5109,19 @@ "step": "1", "className": "", "x": 420, - "y": 2200, + "y": 2460, "wires": [ [ - "c34111aaec734dd9" + "0f3367983bb8e159" ] ] }, { - "id": "888161059eb9c71c", + "id": "96a9febc0928b6f0", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 32, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 35, "width": 3, "height": 1, "name": "tt_angle", @@ -6419,15 +5130,15 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2200, + "y": 2460, "wires": [] }, { - "id": "f4fc72297074c7ae", + "id": "e2c5ea8c16a5ea32", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 4, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, "width": 6, "height": 1, "name": "rotor", @@ -6436,18 +5147,18 @@ "layout": "row-center", "className": "", "x": 90, - "y": 1680, + "y": 1820, "wires": [] }, { - "id": "9b1d8f9e21b34102", + "id": "277037c4716d85bf", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_dir", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 35, + "group": "7a3279eea439bcdd", + "order": 38, "width": 3, "height": 1, "passthru": false, @@ -6459,22 +5170,22 @@ "step": "1", "className": "", "x": 410, - "y": 2240, + "y": 2500, "wires": [ [ - "89dbbe7d99ddbbaf" + "c9d2e31514def4fc" ] ] }, { - "id": "b2e839fe47a32b5f", + "id": "1361134e9847f003", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_dir", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 22, + "group": "7a3279eea439bcdd", + "order": 24, "width": 3, "height": 1, "passthru": false, @@ -6486,19 +5197,19 @@ "step": "1", "className": "", "x": 420, - "y": 2000, + "y": 2260, "wires": [ [ - "204b0a5c8629d78a" + "523717b0f218a5fd" ] ] }, { - "id": "4519daf0b4b28aef", + "id": "6b0d58943ecb8bb2", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 34, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 37, "width": 3, "height": 1, "name": "tt_dir", @@ -6507,15 +5218,15 @@ "layout": "row-spread", "className": "", "x": 750, - "y": 2240, + "y": 2500, "wires": [] }, { - "id": "5f269ea2c8a53f6c", + "id": "08f93dd2aeedb391", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 21, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, "width": 3, "height": 1, "name": "rotor_dir", @@ -6524,74 +5235,47 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2000, + "y": 2260, "wires": [] }, { - "id": "b67dfacfc9a23aa5", + "id": "46b91bef44714366", "type": "link in", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "advanced settings", "links": [ - "62cd775a1c02dac8" + "8750ad979e9ea246" ], "x": 95, - "y": 80, + "y": 100, "wires": [ [ - "9b756a1f9b0e7317" + "89eedf29b404f750" ] ] }, { - "id": "62cd775a1c02dac8", + "id": "8750ad979e9ea246", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "mode": "link", "links": [ - "b67dfacfc9a23aa5" + "46b91bef44714366" ], "x": 955, - "y": 660, + "y": 480, "wires": [] }, { - "id": "9d94dbc523d989a3", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_delay_after", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 16, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0", - "max": "5", - "step": "0.1", - "className": "", - "x": 450, - "y": 2460, - "wires": [ - [ - "b81e238ccd0a04fe" - ] - ] - }, - { - "id": "0558d6eb9a01862e", + "id": "2522f888dc58972f", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_delay_before", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 14, + "group": "d324f0b852c2df0a", + "order": 7, "width": 3, "height": 1, "passthru": false, @@ -6599,53 +5283,26 @@ "topic": "", "topicType": "str", "min": "0", - "max": "5", - "step": "0.1", - "className": "", - "x": 440, - "y": 2500, - "wires": [ - [ - "a0048747e7300bdc" - ] - ] - }, - { - "id": "d47515c9b208bfb7", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_timeout", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 12, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0.01", "max": "1", - "step": "0.01", + "step": "0.02", "className": "", - "x": 420, - "y": 2420, + "x": 430, + "y": 2600, "wires": [ [ - "9b0d5c521a7822cc" + "5c752757090c49d2" ] ] }, { - "id": "89c76766c7552b57", + "id": "30e8df3d616512d8", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_gain", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 22, + "group": "d324f0b852c2df0a", + "order": 11, "width": 3, "height": 1, "passthru": false, @@ -6656,77 +5313,23 @@ "max": "10", "step": "0.1", "className": "", - "x": 410, - "y": 2540, - "wires": [ - [ - "9b26ed02296d27c9" - ] - ] - }, - { - "id": "c385518eb65a1b27", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_awbg_red", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 18, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-10", - "max": "10", - "step": "0.1", - "className": "", - "x": 430, - "y": 2580, - "wires": [ - [ - "b0ac7e9a7c713b84" - ] - ] - }, - { - "id": "5c80833b718d9bf6", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_awbg_blue", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 20, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-10", - "max": "10", - "step": "0.1", - "className": "", - "x": 430, - "y": 2620, + "x": 400, + "y": 2640, "wires": [ [ - "827b1a671a77037d" + "a1769f0277834f6d" ] ] }, { - "id": "5a3826e112fb24e6", + "id": "d855d926df89d65b", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_contrast", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 24, + "group": "d324f0b852c2df0a", + "order": 13, "width": 3, "height": 1, "passthru": false, @@ -6737,23 +5340,24 @@ "max": "5", "step": "0.1", "className": "", - "x": 430, - "y": 2660, + "x": 420, + "y": 2760, "wires": [ [ - "78a1536c167da741" + "1a8b0ba21b4f3005", + "654bc70a18820828" ] ] }, { - "id": "3182ed7ac02b1509", + "id": "7617517dc8ba2859", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_saturation", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 26, + "group": "d324f0b852c2df0a", + "order": 15, "width": 3, "height": 1, "passthru": false, @@ -6764,22 +5368,23 @@ "max": "5", "step": "0.1", "className": "", - "x": 430, - "y": 2700, + "x": 420, + "y": 2800, "wires": [ [ - "fe9a5b68fc8c2077" + "dc8fc962ff7d594b", + "e64feb03a791ca33" ] ] }, { - "id": "7fa6337cdf0a0bc8", + "id": "cbaa23c34e10fae1", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_jpeg_q", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", + "group": "d324f0b852c2df0a", "order": 3, "width": 3, "height": 1, @@ -6791,54 +5396,20 @@ "max": "100", "step": "1", "className": "", - "x": 420, - "y": 2740, + "x": 410, + "y": 2840, "wires": [ [ - "e27d2613e942f344" + "00e7836ccb3c4d0c" ] ] }, { - "id": "08275bf96f87b8ef", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 11, - "width": 3, - "height": 1, - "name": "timeout", - "label": "Timeout", - "format": "", - "layout": "row-spread", - "className": "", - "x": 760, - "y": 2420, - "wires": [] - }, - { - "id": "d2d028df4a139f41", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 15, - "width": 3, - "height": 1, - "name": "delay_after", - "label": "Delay after", - "format": "", - "layout": "row-spread", - "className": "", - "x": 770, - "y": 2460, - "wires": [] - }, - { - "id": "c6a65762aa4ffb7b", + "id": "bbe443b039a14e21", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 13, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, "width": 3, "height": 1, "name": "delay_before", @@ -6846,16 +5417,16 @@ "format": "", "layout": "row-spread", "className": "", - "x": 770, - "y": 2500, + "x": 760, + "y": 2600, "wires": [] }, { - "id": "780323fd4504b855", + "id": "d320ed3d701e6cc2", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 21, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, "width": 3, "height": 1, "name": "gain", @@ -6863,50 +5434,16 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2540, - "wires": [] - }, - { - "id": "780bf08b41202135", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 17, - "width": 3, - "height": 1, - "name": "awbg red", - "label": "AWBG red", - "format": "", - "layout": "row-spread", - "className": "", - "x": 760, - "y": 2580, - "wires": [] - }, - { - "id": "c0faf441fc918538", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 19, - "width": 3, - "height": 1, - "name": "awbg blue", - "label": "AWBG blue", - "format": "", - "layout": "row-spread", - "className": "", - "x": 770, - "y": 2620, + "x": 740, + "y": 2640, "wires": [] }, { - "id": "93d12b447a39c5bb", + "id": "f5834dd4646c8af9", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 23, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, "width": 3, "height": 1, "name": "contrast", @@ -6914,16 +5451,16 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 2660, + "x": 750, + "y": 2760, "wires": [] }, { - "id": "e77e6dcd285d3062", + "id": "ae9a4e19469813ef", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 25, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, "width": 3, "height": 1, "name": "saturation", @@ -6931,15 +5468,15 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 2700, + "x": 750, + "y": 2800, "wires": [] }, { - "id": "a7075bc8d5ee1138", + "id": "bd629d0d31233c8b", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", "order": 2, "width": 3, "height": 1, @@ -6948,18 +5485,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2740, + "x": 740, + "y": 2840, "wires": [] }, { - "id": "282681e7c4351f74", + "id": "e89f61dbe6a6cffe", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "ext", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 3, "width": 2, "height": 1, @@ -6970,19 +5507,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 2900, + "x": 390, + "y": 3000, "wires": [ [ - "b17e82651407d8e0" + "885bc559fafec5f2" ] ] }, { - "id": "da43c58979737fec", + "id": "ece38cb172a12d75", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 2, "width": 4, "height": 1, @@ -6991,18 +5528,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2900, + "x": 730, + "y": 3000, "wires": [] }, { - "id": "ef70d61678fe1f11", + "id": "70014da0b6ab6698", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "light1", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 5, "width": 2, "height": 1, @@ -7013,19 +5550,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 2940, + "x": 390, + "y": 3040, "wires": [ [ - "2c812acffdb330c5" + "f70321c96bf81360" ] ] }, { - "id": "fec56a7e913b21d6", + "id": "29634ea5f6d666df", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 4, "width": 4, "height": 1, @@ -7034,18 +5571,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2940, + "x": 730, + "y": 3040, "wires": [] }, { - "id": "24929b4629f22070", + "id": "2544963852c6881a", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "light2", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 7, "width": 2, "height": 1, @@ -7056,19 +5593,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 2980, + "x": 390, + "y": 3080, "wires": [ [ - "ae0654af69446942" + "95e1603bbd06a69d" ] ] }, { - "id": "7c6bdc0504aa4cc7", + "id": "27903533cd85a59e", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 6, "width": 4, "height": 1, @@ -7077,18 +5614,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2980, + "x": 730, + "y": 3080, "wires": [] }, { - "id": "8c396b060f3d2646", + "id": "a1394401246eb735", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotordir", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 9, "width": 2, "height": 1, @@ -7099,19 +5636,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3020, + "x": 400, + "y": 3120, "wires": [ [ - "58cf48cfacc979fb" + "a8f92ea6bf394640" ] ] }, { - "id": "97568610daccf74a", + "id": "bc0aa4bacdfa94ea", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 8, "width": 4, "height": 1, @@ -7120,18 +5657,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3020, + "x": 740, + "y": 3120, "wires": [] }, { - "id": "a3c58ea48c388215", + "id": "f15ca4518b5f223e", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotorstep", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 11, "width": 2, "height": 1, @@ -7142,19 +5679,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3060, + "x": 400, + "y": 3160, "wires": [ [ - "c7ae206f2fff6810" + "06397bb46b3bb541" ] ] }, { - "id": "6da92aeaeffd95e0", + "id": "0d2924b160e7e383", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 10, "width": 4, "height": 1, @@ -7163,18 +5700,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3060, + "x": 740, + "y": 3160, "wires": [] }, { - "id": "9b5da90eaf6ac562", + "id": "49900bb9047dd965", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotoren", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 13, "width": 2, "height": 1, @@ -7185,19 +5722,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3100, + "x": 400, + "y": 3200, "wires": [ [ - "cfebd4a47a68b319" + "687dcdc1ede11700" ] ] }, { - "id": "12623e4addfa2c22", + "id": "a4d743ca73ee1622", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 12, "width": 4, "height": 1, @@ -7206,18 +5743,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3100, + "x": 740, + "y": 3200, "wires": [] }, { - "id": "f24cb404d7d09f8a", + "id": "5a90224dc998b417", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "ttdir", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 15, "width": 2, "height": 1, @@ -7228,19 +5765,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 3140, + "x": 390, + "y": 3240, "wires": [ [ - "90f4d220928e4727" + "e220740c0d38ccb0" ] ] }, { - "id": "542bfb9d92935c2c", + "id": "67dc1b544c4ddf9f", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 14, "width": 4, "height": 1, @@ -7249,18 +5786,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 3140, + "x": 730, + "y": 3240, "wires": [] }, { - "id": "1f79467df98ce894", + "id": "d2364ab09627fe94", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "ttstep", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 17, "width": 2, "height": 1, @@ -7271,19 +5808,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 3180, + "x": 390, + "y": 3280, "wires": [ [ - "b05e1e612887f9c2" + "79d7e5a705ab813a" ] ] }, { - "id": "170d3b925f7745cc", + "id": "145b67ac40721ba6", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 16, "width": 4, "height": 1, @@ -7292,18 +5829,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 3180, + "x": 730, + "y": 3280, "wires": [] }, { - "id": "65b0130e390c2e67", + "id": "eef25405472acfee", "type": "ui_text_input", - "z": "017bd4e4a428bee5", - "name": "tten", + "z": "e43a27722b508115", + "name": "endstop1", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 19, "width": 2, "height": 1, @@ -7314,39 +5851,39 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 3220, + "x": 400, + "y": 3320, "wires": [ [ - "fe22723ce5a3495f" + "12d20f2274bcc511" ] ] }, { - "id": "10ac340984418a58", + "id": "35eb252a41413531", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 18, "width": 4, "height": 1, - "name": "tten", - "label": "Turntable enable", + "name": "endstop1", + "label": "Endstop Rotor", "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 3220, + "x": 740, + "y": 3320, "wires": [] }, { - "id": "661614f5bd2c71d6", + "id": "74e455136b5ca5dd", "type": "ui_text_input", - "z": "017bd4e4a428bee5", - "name": "endstop1", + "z": "e43a27722b508115", + "name": "endstop2", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 21, "width": 2, "height": 1, @@ -7357,78 +5894,35 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3260, + "x": 400, + "y": 3360, "wires": [ [ - "2af447a6905b83bc" + "a4a89668ce4c9f05" ] ] }, { - "id": "c18b55859dae5f85", + "id": "3a74f653800eb831", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 20, "width": 4, "height": 1, - "name": "endstop1", - "label": "Endstop 1", - "format": "", - "layout": "row-spread", - "className": "", - "x": 760, - "y": 3260, - "wires": [] - }, - { - "id": "e23a396162026618", - "type": "ui_text_input", - "z": "017bd4e4a428bee5", "name": "endstop2", - "label": "", - "tooltip": "", - "group": "644b3bcc903d46ca", - "order": 23, - "width": 2, - "height": 1, - "passthru": false, - "mode": "number", - "delay": "0", - "topic": "topic", - "sendOnBlur": true, - "className": "", - "topicType": "msg", - "x": 420, - "y": 3300, - "wires": [ - [ - "787a128f84f747c0" - ] - ] - }, - { - "id": "82c1a33014d003e9", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", - "order": 22, - "width": 4, - "height": 1, - "name": "endstop1", - "label": "Endstop 2", + "label": "Endstop Turntable", "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3300, + "x": 740, + "y": 3360, "wires": [] }, { - "id": "5255759a7c5b2a74", + "id": "5fcef1cb2e9e4788", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -7441,37 +5935,37 @@ "topic": "", "name": "confirm", "x": 680, - "y": 660, + "y": 480, "wires": [ [ - "15fd1c9e5610cb85" + "29745a36fc157f3f" ] ] }, { - "id": "8be8015931c663cc", + "id": "f06a7bcad524e9f9", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", "outputs": 1, "x": 530, - "y": 660, + "y": 480, "wires": [ [ - "5255759a7c5b2a74" + "5fcef1cb2e9e4788" ] ] }, { - "id": "9d464b2ba1edaf48", + "id": "f455fb39039617ae", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_rotation", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 10, + "group": "d324f0b852c2df0a", + "order": 5, "width": 3, "height": 1, "passthru": false, @@ -7482,20 +5976,20 @@ "max": "270", "step": "90", "className": "", - "x": 420, - "y": 2780, + "x": 410, + "y": 2880, "wires": [ [ - "b7d3fe0c0b40b3e1" + "3019576de193d9d6" ] ] }, { - "id": "db98b95693ebce63", + "id": "fdfbc900fe424eb9", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 9, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, "width": 3, "height": 1, "name": "cam_rot", @@ -7503,14 +5997,14 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 2780, + "x": 750, + "y": 2880, "wires": [] }, { - "id": "6659121906897a1f", + "id": "c3699d6b9664ccca", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7519,17 +6013,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1800, + "y": 2060, "wires": [ [ - "1d4230b3d9b93f63" + "dfdebe10dbf0e198" ] ] }, { - "id": "0bb56b1edb12c2cf", + "id": "78e256083f59f66f", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7538,15 +6032,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1800, + "y": 2060, "wires": [ [] ] }, { - "id": "569829eeff715c33", + "id": "0f9141b401322374", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7555,17 +6049,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1920, + "y": 2180, "wires": [ [ - "1ab34b0a78b2c577" + "9a56c087d941f1da" ] ] }, { - "id": "249f44c3a87793ba", + "id": "29f576be9e292232", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7574,15 +6068,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1920, + "y": 2180, "wires": [ [] ] }, { - "id": "c997e60519341afd", + "id": "23e3099b34c4e475", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7591,17 +6085,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1960, + "y": 2220, "wires": [ [ - "1b3ac50d2c6600c6" + "0dfc86d90258f9bb" ] ] }, { - "id": "e0d7c36daa42b3f3", + "id": "c4b5a38c5c1df3d2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7610,15 +6104,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1960, + "y": 2220, "wires": [ [] ] }, { - "id": "59ecf3a22cd3a669", + "id": "79a14162ac805fac", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7627,17 +6121,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2000, + "y": 2260, "wires": [ [ - "b2e839fe47a32b5f" + "1361134e9847f003" ] ] }, { - "id": "204b0a5c8629d78a", + "id": "523717b0f218a5fd", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7646,15 +6140,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2000, + "y": 2260, "wires": [ [] ] }, { - "id": "15f02421b30a9ab6", + "id": "f5cf780f3fa8997e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", "outputs": 1, @@ -7663,17 +6157,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1840, + "y": 2100, "wires": [ [ - "8c1a92f2dcc976c7" + "b03e8b51187e88eb" ] ] }, { - "id": "bb54bbdae6690576", + "id": "11fd3363416433f9", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7682,15 +6176,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1840, + "y": 2100, "wires": [ [] ] }, { - "id": "58928befcc61b1f7", + "id": "02060b3f3b294563", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, @@ -7699,17 +6193,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1880, + "y": 2140, "wires": [ [ - "f9b51424edb0491c" + "543e1690693acbeb" ] ] }, { - "id": "ea87ecfd2af3cc7f", + "id": "e8b24efb0f30288e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7718,34 +6212,34 @@ "finalize": "", "libs": [], "x": 630, - "y": 1880, + "y": 2140, "wires": [ [] ] }, { - "id": "27bc56f273360ac7", + "id": "de1ad8b27b72a5ac", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nsteps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", "outputs": 1, - "noerr": 0, + "noerr": 4, "initialize": "", "finalize": "", "libs": [], "x": 290, - "y": 2040, + "y": 2300, "wires": [ [ - "0c50fdbb5ac3c373" + "c6642c7470d3820c" ] ] }, { - "id": "f46ced86106306c8", + "id": "ed4d587cb4feb064", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7754,17 +6248,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2160, + "y": 2420, "wires": [ [ - "6ef996f8a36f94c2" + "721b9680a3fa460e" ] ] }, { - "id": "4339704cd8552eb3", + "id": "5b02160c33605ae7", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7773,17 +6267,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2200, + "y": 2460, "wires": [ [ - "16e9a3a71c4bb916" + "1610895f430b9aca" ] ] }, { - "id": "1ac53bb6150645fe", + "id": "304c135ec09801e3", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7792,17 +6286,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2240, + "y": 2500, "wires": [ [ - "9b1d8f9e21b34102" + "277037c4716d85bf" ] ] }, { - "id": "9b89eb1eaf333c10", + "id": "a91dcbe0f9a2416a", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", "outputs": 1, @@ -7811,17 +6305,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2080, + "y": 2340, "wires": [ [ - "2647111c06f2055d" + "6aae9d4fddf08cc0" ] ] }, { - "id": "2e8927be0e235fa1", + "id": "6b2eb1cb95e573f9", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, @@ -7830,17 +6324,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2120, + "y": 2380, "wires": [ [ - "56bc3b93af2ebe16" + "10687d331a732790" ] ] }, { - "id": "485a4bed5a6bea23", + "id": "eef89545ec0f6aa8", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7849,15 +6343,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2040, + "y": 2300, "wires": [ [] ] }, { - "id": "2c000bd53cdb98ca", + "id": "b1b4678827d3a6dd", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7866,15 +6360,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2160, + "y": 2420, "wires": [ [] ] }, { - "id": "c34111aaec734dd9", + "id": "0f3367983bb8e159", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7883,15 +6377,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2200, + "y": 2460, "wires": [ [] ] }, { - "id": "89dbbe7d99ddbbaf", + "id": "c9d2e31514def4fc", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7900,15 +6394,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2240, + "y": 2500, "wires": [ [] ] }, { - "id": "fb8145a9f8d4f7b2", + "id": "e50492d1e18f43c6", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7917,15 +6411,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2080, + "y": 2340, "wires": [ [] ] }, { - "id": "35422077b53da9bf", + "id": "af88b9da72917d62", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7934,1119 +6428,1171 @@ "finalize": "", "libs": [], "x": 630, - "y": 2120, + "y": 2380, "wires": [ [] ] }, { - "id": "d5308090f2b7971a", + "id": "43fe948b3e7234e2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", - "func": "var file = 'cam_timeout'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2420, + "x": 280, + "y": 2600, "wires": [ [ - "d47515c9b208bfb7" + "2522f888dc58972f" ] ] }, { - "id": "9b0d5c521a7822cc", + "id": "5c752757090c49d2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_timeout'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2420, + "x": 620, + "y": 2600, "wires": [ [] ] }, { - "id": "694d1068bea15171", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 2460, - "wires": [ - [ - "9d94dbc523d989a3" - ] - ] - }, - { - "id": "cec3e5e78a40476b", + "id": "435681b3f7625a7e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", - "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2500, + "x": 280, + "y": 2640, "wires": [ [ - "0558d6eb9a01862e" + "30e8df3d616512d8" ] ] }, { - "id": "b81e238ccd0a04fe", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 2460, - "wires": [ - [] - ] - }, - { - "id": "a0048747e7300bdc", + "id": "a1769f0277834f6d", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2500, + "x": 620, + "y": 2640, "wires": [ [] ] }, { - "id": "6f524f9370a18482", + "id": "1de07c7d285cbaf3", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", - "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2540, + "x": 280, + "y": 2760, "wires": [ [ - "89c76766c7552b57" + "d855d926df89d65b" ] ] }, { - "id": "9b26ed02296d27c9", + "id": "1a8b0ba21b4f3005", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2540, + "x": 620, + "y": 2760, "wires": [ [] ] }, { - "id": "1f87f473e327c3cc", + "id": "ebc9e283468eda31", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", - "func": "var file = 'cam_awbg_red'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2580, + "x": 280, + "y": 2800, "wires": [ [ - "c385518eb65a1b27" + "7617517dc8ba2859" ] ] }, { - "id": "b0ac7e9a7c713b84", + "id": "dc8fc962ff7d594b", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_awbg_red'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2580, + "x": 620, + "y": 2800, "wires": [ [] ] }, { - "id": "cff7ac5f1e061855", + "id": "60d641613527c736", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_awbg_blue'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2620, + "x": 280, + "y": 2840, "wires": [ [ - "5c80833b718d9bf6" + "cbaa23c34e10fae1" ] ] }, { - "id": "827b1a671a77037d", + "id": "00e7836ccb3c4d0c", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_awbg_blue'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2620, + "x": 620, + "y": 2840, "wires": [ [] ] }, { - "id": "cf854461c37ca54f", + "id": "7f24c0c34a88ba04", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2660, + "x": 280, + "y": 2880, "wires": [ [ - "5a3826e112fb24e6" + "f455fb39039617ae" ] ] }, { - "id": "78a1536c167da741", + "id": "3019576de193d9d6", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2660, + "x": 620, + "y": 2880, "wires": [ [] ] }, { - "id": "ba10e04dd1761692", + "id": "77bb7dc529d63a7e", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2700, + "x": 270, + "y": 3000, "wires": [ [ - "3182ed7ac02b1509" + "e89f61dbe6a6cffe" ] ] }, { - "id": "fe9a5b68fc8c2077", + "id": "885bc559fafec5f2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2700, + "x": 590, + "y": 3000, "wires": [ [] ] }, { - "id": "a69d216114f908a5", + "id": "cc6dabe017a9c8a8", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2740, + "x": 270, + "y": 3320, "wires": [ [ - "7fa6337cdf0a0bc8" + "eef25405472acfee" ] ] }, { - "id": "e27d2613e942f344", + "id": "12d20f2274bcc511", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2740, + "x": 590, + "y": 3320, "wires": [ [] ] }, { - "id": "f02d4a036a225e87", + "id": "dcb9fed8122759fd", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2780, + "x": 270, + "y": 3040, "wires": [ [ - "9d464b2ba1edaf48" + "70014da0b6ab6698" ] ] }, { - "id": "b7d3fe0c0b40b3e1", + "id": "f70321c96bf81360", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2780, + "x": 590, + "y": 3040, "wires": [ [] ] }, { - "id": "612cccacda1a65aa", + "id": "013d2057c2347a62", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2900, + "x": 270, + "y": 3080, "wires": [ [ - "282681e7c4351f74" + "2544963852c6881a" ] ] }, { - "id": "b17e82651407d8e0", + "id": "95e1603bbd06a69d", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 2900, + "x": 590, + "y": 3080, "wires": [ [] ] }, { - "id": "3b126549c03a872e", + "id": "f88bbf11d5aa9a14", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_endstop1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3260, + "x": 270, + "y": 3120, "wires": [ [ - "661614f5bd2c71d6" + "a1394401246eb735" ] ] }, { - "id": "2af447a6905b83bc", + "id": "a8f92ea6bf394640", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_endstop1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3260, + "x": 590, + "y": 3120, "wires": [ [] ] }, { - "id": "954db931f87894ee", + "id": "301af70731e096e5", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2940, + "x": 270, + "y": 3160, "wires": [ [ - "ef70d61678fe1f11" + "f15ca4518b5f223e" ] ] }, { - "id": "2c812acffdb330c5", + "id": "06397bb46b3bb541", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 2940, + "x": 590, + "y": 3160, "wires": [ [] ] }, { - "id": "6682c8057e89d087", + "id": "0456a9ec4c236c9e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2980, + "x": 270, + "y": 3200, "wires": [ [ - "24929b4629f22070" + "49900bb9047dd965" ] ] }, { - "id": "ae0654af69446942", + "id": "687dcdc1ede11700", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 2980, + "x": 590, + "y": 3200, "wires": [ [] ] }, { - "id": "015be401d08047d2", + "id": "09d37ba08ec0f163", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3020, + "x": 270, + "y": 3240, "wires": [ [ - "8c396b060f3d2646" + "5a90224dc998b417" ] ] }, { - "id": "58cf48cfacc979fb", + "id": "37d954a4cf7e87ea", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3020, + "x": 270, + "y": 3280, "wires": [ - [] + [ + "d2364ab09627fe94" + ] ] }, { - "id": "1c6c0f8b9ac95659", + "id": "e220740c0d38ccb0", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3060, + "x": 590, + "y": 3240, "wires": [ - [ - "a3c58ea48c388215" - ] + [] ] }, { - "id": "c7ae206f2fff6810", + "id": "79d7e5a705ab813a", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3060, + "x": 590, + "y": 3280, "wires": [ [] ] }, { - "id": "dcee66c0d56c6934", + "id": "21dc963d967d9c99", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3100, + "x": 270, + "y": 3360, "wires": [ [ - "9b5da90eaf6ac562" + "74e455136b5ca5dd" ] ] }, { - "id": "cfebd4a47a68b319", + "id": "a4a89668ce4c9f05", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3100, + "x": 590, + "y": 3360, "wires": [ [] ] }, { - "id": "6ec7d85bb17eb159", + "id": "22ef66b0e2058be2", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3140, + "x": 270, + "y": 360, "wires": [ [ - "f24cb404d7d09f8a" + "cb3437ec113e1b6f" ] ] }, { - "id": "4f42d02a3776a006", + "id": "9ce01c8ba97932c1", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3180, + "x": 270, + "y": 400, "wires": [ [ - "1f79467df98ce894" + "60fd0adce1cfeb82" ] ] }, { - "id": "5d70f4715c9a5ae1", + "id": "81356177176eebcf", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_tt_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3220, + "x": 270, + "y": 480, "wires": [ [ - "65b0130e390c2e67" + "f6d6cc35679ede63" ] ] }, { - "id": "90f4d220928e4727", + "id": "b78346ca3ce70c68", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3140, + "x": 270, + "y": 320, "wires": [ - [] + [ + "f0d8dbcca76a1926" + ] ] }, { - "id": "b05e1e612887f9c2", + "id": "e95b86cbac1b03b9", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3180, + "x": 550, + "y": 320, "wires": [ [] ] }, { - "id": "fe22723ce5a3495f", + "id": "3e4c15d7b538f816", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'pin_tt_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3220, + "x": 670, + "y": 1540, "wires": [ - [] + [ + "3bf622f344172721" + ] ] }, { - "id": "58bbe9fc41e0d7b9", + "id": "0f0871baf322b6d0", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_endstop2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 290, - "y": 3300, + "y": 1820, "wires": [ [ - "e23a396162026618" + "6ebd15c61a5ca891" ] ] }, { - "id": "787a128f84f747c0", + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_endstop2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3300, + "x": 630, + "y": 1820, "wires": [ [] ] }, { - "id": "78351089ee9ebeaf", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 340, + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, "wires": [ [ - "40dee936a9abac0d" + "acd10a4c99ee8063" ] ] }, { - "id": "5fba78ae65eaaf5d", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 380, + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, "wires": [ [ - "4fd9bb53fdb51a25" + "031d7697768d0e77" ] ] }, { - "id": "67206663b3881868", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 660, + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, "wires": [ [ - "c833f6243a059d83" + "be1954dd71d2c94c" ] ] }, { - "id": "3492754252645e62", + "id": "edb1c8fae8b65c82", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'camera'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 420, + "x": 290, + "y": 1860, "wires": [ [ - "a2c1dba3e67be015", - "6f3d403e157163e4" + "3ad0f0f206e4a873" ] ] }, { - "id": "d16525a31223bc42", + "id": "031d7697768d0e77", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'model'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 620, + "x": 630, + "y": 1860, "wires": [ - [ - "80b579a4220e5c23", - "c6138801b30f091d" - ] + [] ] }, { - "id": "f99ec8781a33ec7d", + "id": "462a8f3ca75fc3c8", "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 300, + "x": 290, + "y": 1900, "wires": [ [ - "7dc39bd847d16ded" + "3b6d759ed5be647f" ] ] }, { - "id": "5f849178998d9082", + "id": "be1954dd71d2c94c", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "if(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 550, - "y": 300, + "x": 630, + "y": 1900, "wires": [ [] ] }, { - "id": "725fd0cab0bddc0e", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'hostname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 250, - "y": 940, + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, "wires": [ [ - "49259adad52fc214" + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88" ] ] }, { - "id": "49259adad52fc214", - "type": "ui_text_input", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Hostname", - "tooltip": "", - "group": "0fe66c9190b8a87c", - "order": 6, - "width": 6, - "height": 1, - "passthru": false, - "mode": "text", - "delay": "0", - "topic": "Change hostname to:", - "sendOnBlur": true, - "className": "", - "topicType": "str", - "x": 530, + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, "y": 940, "wires": [ [ - "8001f7c361de7d8c" + "ded3086945a6d4b5", + "6ea3cdab41f20f92" ] ] }, { - "id": "51521bc6eb44cde5", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.enabled = false\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 250, - "y": 980, + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, + "wires": [ + [ + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd" + ] + ] + }, + { + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2540, "wires": [ [ - "59c9f67283ba1709" + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" ] ] }, { - "id": "2bb52656f9554dab", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "ssid = msg.payload\nmsg.topic = 'Add wifi network (' + ssid + ')'\nmsg.payload = 'Enter Wifi password:'\nmsg.ssid = ssid\n\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 650, - "y": 980, + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3000, "wires": [ [ - "ebcc98685059b9d4" + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8", + "21dc963d967d9c99" ] ] }, { - "id": "ebce67b739d1891f", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "chk/change hostname", - "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n pass\n\nwith open('/etc/hostname', 'r') as file:\n old_hostname = file.read().replace('\\n','')\n\nhostname = msg['hostname']\nif len(hostname) < 4 :\n msg['payload'] = ' '\n msg['topic'] = 'ERROR - Hostname NOT changed'\n return msg\n \n\nwith open('/etc/hostname', 'w+') as file:\n file.write(hostname)\nos.system('echo ' + hostname + ' | tee /etc/hostname')\nwith open('/etc/hosts', 'r') as file:\n temp = file.read()\ntemp = temp.replace(old_hostname,hostname)\nwith open('/etc/hosts', 'w') as file:\n file.write(temp)\nos.system('hostnamectl set-hostname ' + hostname)\nos.system('systemctl restart avahi-daemon')\nsave('hostname',hostname)\nmsg['payload'] = hostname\nmsg['topic'] = 'Success - Hostname changed'\nreturn msg\n", - "outputs": 1, - "x": 1140, - "y": 940, + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 620, "wires": [ [ - "03732a7d3b0c95aa" + "53e6681d7254d484" ] ] }, { - "id": "667ac2aba819f506", + "id": "53e6681d7254d484", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", "sendall": true, "outputs": 1, - "ok": "OK", - "cancel": "Cancel", + "ok": "No", + "cancel": "Yes", "raw": false, "className": "", "topic": "", - "name": "Confirm", - "x": 920, - "y": 940, - "wires": [ - [ - "ebce67b739d1891f" - ] - ] - }, - { - "id": "8001f7c361de7d8c", - "type": "change", - "z": "017bd4e4a428bee5", "name": "", - "rules": [ - { - "t": "set", - "p": "hostname", - "pt": "msg", - "to": "payload", - "tot": "msg" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 710, - "y": 940, - "wires": [ - [ - "667ac2aba819f506" - ] - ] - }, - { - "id": "9bb0adbd716ce347", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "reboot", - "links": [ - "16c76929f88df841", - "fe3a855fee9e28c6" - ], - "x": 155, - "y": 720, + "x": 270, + "y": 620, "wires": [ [ - "d114f4d4d7f31981", - "cc3cb10f2ea3f8b8" + "c11e79cfa7bc10b7" ] ] }, { - "id": "f9efcb87b74abbd4", + "id": "c11e79cfa7bc10b7", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", - "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 670, - "y": 1520, + "x": 410, + "y": 620, "wires": [ [ - "510dbe4d76253bd6" + "307782d10c1acdaf" ] ] }, { - "id": "adc206aa8edd1e41", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "OSC", - "group": "db43d646.2074c8", - "order": 2, - "width": 3, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 620, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, "className": "", - "icon": "fa-question-circle", - "payload": "

Files&Cloud

Refresh

You can refresh the status of the processing of your files in the OpenScanCloud. Make sure to read and agree the terms of use (in settings menu) before using the OpenScanCloud. Do not spam this button, as this might lead to temporary/permanent suspension of your IP address.

The status (in the table) of the individual sets in the file list will be updated to one of the following:

Created - you started the upload of your image set. If you are stuck on this status, please try to restart the upload.

Initialized - all files have been uploaded and processing will start as soon as possible

File approved - the server received and verified your files

Processing started - your files are currently being processed

Processing failed - there are various reasons why processing might fail. Please check the email for more details or contact me at cloud@openscan.eu

processing done - check your email, where you should find a link to the 3d model :)

Status (on the right column)

Indicates, what the device is currently up to.

Refreshing - updating all image set's status

Uploading - while transferring the image set to the OpenScanCloud servers. If the upload freezes, be patient. If nothing happens, reboot the device and restart the upload.

Project started - when the upload of a set was successful

Zipping - files larger then 200mb have to be split and re-zipped before uploading to the OpenScanCloud, the process might take a while depending on the filesize.

Combining - two sets into one might take up to a minute.

Set

select a set from the file list by clicking on a row in the table

Download

Download the selected set from the OpenScan device to your computer/mobile/tablet

Upload

Upload the selected file to the OpenScanCloud

Combine

In order to combine two sets, select one set. Click the combine button and select the second set. A pop-up will appear, and you can confirm the operation. All images from the two sets will be merged into one set. The original image sets will be deleted!

Delete Set/All

Please keep in mind, that the memory of the SD card is relatively small, and thus you will have to delete individual or all photo sets from time to time.

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 590, - "y": 200, + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, "wires": [ - [ - "f304680180a23479" - ] + [] ] }, { - "id": "45df91cae421e8e1", + "id": "cca3300a8f0daf4d", "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Scan_settings", - "group": "7aaf184330605300", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", "order": 1, "width": 6, "height": 1, @@ -9057,726 +7603,778 @@ "bgcolor": "transparent", "className": "", "icon": "fa-question-circle", - "payload": "

Scan Settings

Current Status

--READY-- - everything is okay and ready to go :)

Routine-preparing - before starting the routine some time might pass depending on the number of photos

Routine-stopping - manually ending the routine by pressing the stop button

Routine-Photo X/Y - Showing the progress of the routine

No Camera Found - please check the camera ribbon cable

Error: XXX - Please contact info@openscan.eu or post an issue on Github.com

Projectname

Each photo set will be saved using the following pattern  YYYY-MM-DD_hh-mm-ss_projectname.zip (e.g. 2022-04-05_12.12.12_toysoldier.zip). Keep your files organized by giving each set a new projectname. If not specified 'default' will be used.

Rotor

Moving the rotor by increments of 5°. Please make sure to start the routine with the camera in the horizontal position.

Turntable

Moving the turntable by increments of 15°.

Ringlight

Use the ring light for shadow-free illumination. It is highly recommended to use the polarizer in order to avoid reflections. Note, that the polarizer will absorb 75% of the light, so you might need to use both ring lights.

Photos

Set the number of photos for the current set. 60-120 photos should be more than enough for most objects. If the reconstruction fails or is very bad with 60 photos, increasing the number of photos will not help!

Shutter

Again: Less is more! If the value is too high, some areas might get overexposed and thus, the software will not be able to recognize the surface feature of the object. Here are some reference values:

- no polarizer: 5-20ms

- mostly white object,  with polarizer + one ringlight: 50-200ms

Crop X/Y

Make sure to use the right object holder to place the object in the middle of the screen. Try to crop as many unnecessary areas as possible. This will greatly lower the file size and resulting transfer and reconstruction times!

Start/Stop

Use the buttons to start/stop the routine

Reboot/Shutdown

In case of an error, try to restart the device. Always use the shutdown button before powering-off the device!

", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 760, - "y": 120, + "x": 750, + "y": 180, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "e9677b85856b5873", + "id": "654bc70a18820828", "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "Reset rfkill", - "func": "from os import system\nif \"Interface doesn't support scanning\" in msg['payload']:\n system('rfkill unblock all')\n system('ifconfig wlan0 up')\n return msg", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/picam2_contrast?contrast=\" + str(msg['payload']))", "outputs": 1, - "x": 390, - "y": 1100, + "x": 660, + "y": 2720, "wires": [ [] ] }, { - "id": "91fe20cb16f54293", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/picam2_saturation?saturation=\" + str(msg['payload']))", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 1680, + "x": 660, + "y": 2680, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2560, "wires": [ [ - "327c8bdde31033a4" + "e612073aded01a8f" ] ] }, { - "id": "add3e998b097c54f", + "id": "0d92559980944ae3", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 7, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, "width": 3, "height": 1, - "name": "rotor_anglemin", - "label": "Min Angle", + "name": "delay_after", + "label": "Delay after", "format": "", - "layout": "row-left", + "layout": "row-spread", "className": "", - "x": 780, - "y": 1680, + "x": 760, + "y": 2560, "wires": [] }, { - "id": "da286366433c83a0", + "id": "6281b2e6e081104d", + "type": "function", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2560, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 1680, + "x": 620, + "y": 2560, "wires": [ [] ] }, { - "id": "327c8bdde31033a4", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "rotor_anglemin", - "label": "", + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 520, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 8, - "width": 3, + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, "height": 1, "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-90", - "max": "90", - "step": "5", + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, "className": "", - "x": 440, - "y": 1680, + "topicType": "str", + "x": 210, + "y": 980, "wires": [ [ - "da286366433c83a0" + "a7d233f984009e2e" ] ] }, { - "id": "94288df4c6756197", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "rotor_anglemax", - "label": "", - "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 10, - "width": 3, + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", + "tooltip": "", + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, "height": 1, "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-90", - "max": "90", - "step": "5", + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, "className": "", - "x": 440, - "y": 1720, + "topicType": "str", + "x": 220, + "y": 1020, "wires": [ [ - "e531ffe3dcf34eb4" + "a7d233f984009e2e" ] ] }, { - "id": "4702a4a09124e27d", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "rotor_anglestart", - "label": "", + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", "tooltip": "", - "group": "d49a6dfd7fb17096", + "group": "8ab79a98e536e0d6", "order": 6, - "width": 3, + "width": 6, "height": 1, "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-90", - "max": "90", - "step": "5", + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, "className": "", - "x": 440, - "y": 1760, + "topicType": "str", + "x": 240, + "y": 1060, "wires": [ [ - "9ce407cb16f0419a" + "a7d233f984009e2e" ] ] }, { - "id": "2cf946c7aab2cbb4", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 1720, + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, "wires": [ [ - "94288df4c6756197" + "a7d233f984009e2e" ] ] }, { - "id": "e531ffe3dcf34eb4", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 1720, - "wires": [ - [] - ] + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] }, { - "id": "4da5f650d3845baa", + "id": "a7d233f984009e2e", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 1760, + "x": 440, + "y": 980, "wires": [ [ - "4702a4a09124e27d" + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" ] ] }, { - "id": "9ce407cb16f0419a", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 1760, - "wires": [ - [] - ] - }, - { - "id": "fda776c5aa642867", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 9, - "width": 3, - "height": 1, - "name": "rotor_anglemax", - "label": "Max Angle", - "format": "", - "layout": "row-left", - "className": "", - "x": 780, - "y": 1720, - "wires": [] - }, - { - "id": "6e9af48a1c4c58c6", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 5, - "width": 3, - "height": 1, - "name": "rotor_anglestart", - "label": "Start Angle", - "format": "", - "layout": "row-left", - "className": "", - "x": 780, - "y": 1760, - "wires": [] - }, - { - "id": "9b2bc9849aee310b", + "id": "65518f3d4e3095e5", "type": "link in", - "z": "017bd4e4a428bee5", - "name": "changeHostname", + "z": "e43a27722b508115", + "name": "link in 1", "links": [ - "ec2db55a99bbe3ee", - "d5175561293ef490", - "960912e90ba5b5bc" + "200d4b9951b6e066" ], - "x": 835, - "y": 900, + "x": 85, + "y": 980, "wires": [ [ - "8b9e3781511e9231" + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" ] ] }, { - "id": "8b9e3781511e9231", + "id": "9b851aa999e86fd7", "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "chk", - "func": "with open('/etc/hostname', 'r') as file:\n old_hostname = file.read().replace('\\n','')\nif old_hostname == 'raspberrypi':\n msg['hostname'] = 'openscan'\n msg['payload'] = 'OK'\n return msg", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", "outputs": 1, - "x": 930, - "y": 900, + "x": 670, + "y": 980, "wires": [ [ - "ebce67b739d1891f" + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" ] ] }, { - "id": "3fcbd9fe3acc3fb7", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "scan_arducam", - "group": "90223f7ddc082321", - "order": 1, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, "className": "", - "icon": "fa-question-circle", - "payload": "

Focus Settings

MF - Manual Focus

By default, the switch is 'off', which means that autofocus is active. For small objects, it might be necessary to use manual focus: activate the switch and set the focus by pressing + and - accordingly. The distance is measured between the camera lens and the focal plane (which should be in the center or slightly in front of the center of the object). Be aware, that the distance value is only a rough estimate (mm)

ST - Stacking

Stacking is disabled by default. Once activated, you will be able to set the following:

Stacksize - defines the number of photos between the minimal and the maximal focal distance

SET press this button to set the maximal/minimal focal distance. Pressing the button a third time will re-set the values.

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 760, - "y": 160, + "topic": "", + "name": "", + "x": 870, + "y": 980, "wires": [ - [ - "f304680180a23479" - ] + [] ] }, { - "id": "6d68cccec646e0a0", + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, + "wires": [] + }, + { + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", + "links": [ + "592ec13d8f8923a9" + ], + "x": 815, + "y": 1020, + "wires": [] + }, + { + "id": "1eef47e0074545a9", "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "enable routine", - "func": "msg_enable = {}\nmsg_disable = {}\n\nmsg_enable['enabled'] = True\nmsg_disable['enabled'] = False\n\nif msg['payload'] == 'external':\n return msg_enable, msg_disable\nif msg['payload'] == 'gphoto':\n return msg_enable, msg_enable, msg_disable\n\nreturn msg_enable", - "outputs": 3, - "x": 560, - "y": 440, + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, "wires": [ [ - "a0ba1aa77c5c8b7c" - ], - [ - "a42c12e94f65fa01" + "c994c779e4bad800", + "36890eb99a2ca1cf" ], - [ - "2d76e5617f13cd6c" - ] + [] ] }, { - "id": "a0ba1aa77c5c8b7c", - "type": "link out", - "z": "017bd4e4a428bee5", + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", "name": "", - "mode": "link", - "links": [ - "2aea1727dbea76ce", - "4f212b44aa487945", - "65cef204b16f8741", - "917a194be245384a" + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } ], - "x": 675, - "y": 420, - "wires": [] + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, + "wires": [ + [ + "1eef47e0074545a9" + ] + ] }, { - "id": "a42c12e94f65fa01", - "type": "link out", - "z": "017bd4e4a428bee5", + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", "name": "", - "mode": "link", - "links": [ - "2aea1727dbea76ce", - "4f212b44aa487945", - "65cef204b16f8741", - "917a194be245384a" - ], - "x": 715, - "y": 440, + "x": 670, + "y": 1020, "wires": [] }, { - "id": "2d76e5617f13cd6c", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "65cef204b16f8741" - ], - "x": 675, - "y": 460, + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, "wires": [] }, { - "id": "bd80ec228fb9a86d", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 135, - "y": 340, + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, "wires": [ [ - "78351089ee9ebeaf", - "5fba78ae65eaaf5d", - "3492754252645e62", - "d16525a31223bc42", - "67206663b3881868" + "85ad07b8f973bbe2" ] ] }, { - "id": "65b38bfeb3fee710", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 155, - "y": 760, - "wires": [ - [ - "cc3cb10f2ea3f8b8" - ] - ] + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "endstop_angle", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2020, + "wires": [] }, { - "id": "d3fc91d87d5d5f62", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 135, - "y": 940, + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, "wires": [ - [ - "725fd0cab0bddc0e" - ] + [] ] }, { - "id": "cc9c4092edeb43cc", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 135, - "y": 1020, + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, "wires": [ [ - "27c6b221c90ed9e1", - "f393400.d87dcc" + "6b7245c3dcb694c8" ] ] }, { - "id": "f0b355967b33dfee", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 175, - "y": 1600, + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, "wires": [ [ - "91fe20cb16f54293", - "2cf946c7aab2cbb4", - "4da5f650d3845baa", - "6659121906897a1f", - "15f02421b30a9ab6", - "58928befcc61b1f7", - "569829eeff715c33", - "c997e60519341afd", - "59ecf3a22cd3a669", - "27bc56f273360ac7", - "9b89eb1eaf333c10", - "2e8927be0e235fa1", - "f46ced86106306c8", - "4339704cd8552eb3", - "1ac53bb6150645fe", - "0d48bb415c584420", - "b6e420121e6466e7" + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" ] ] }, { - "id": "d7c1fb4c028b21a5", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 155, - "y": 2280, + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, "wires": [ [ - "d5308090f2b7971a", - "694d1068bea15171", - "cec3e5e78a40476b", - "6f524f9370a18482", - "1f87f473e327c3cc", - "cff7ac5f1e061855", - "cf854461c37ca54f", - "ba10e04dd1761692", - "a69d216114f908a5", - "f02d4a036a225e87", - "1efd4a05aee0b86c", - "6841e5a392f0fb4f" + "253feafa5a2f8b1d" ] ] }, { - "id": "a67c18aaca2f5fa5", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 155, - "y": 2900, + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, "wires": [ - [ - "612cccacda1a65aa", - "954db931f87894ee", - "6682c8057e89d087", - "015be401d08047d2", - "1c6c0f8b9ac95659", - "dcee66c0d56c6934", - "6ec7d85bb17eb159", - "4f42d02a3776a006", - "5d70f4715c9a5ae1", - "3b126549c03a872e", - "58bbe9fc41e0d7b9" - ] + [] ] }, { - "id": "c6d3821bc7f43f8e", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Reset default", - "group": "4fe6b4c0ade0938a", - "order": 14, - "width": 6, + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, "height": 1, - "passthru": false, - "label": "Restore default settings", - "tooltip": "", - "color": "red", - "bgcolor": "", + "name": "rotor_enable_endstop", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", "className": "", - "icon": "", - "payload": "This can not be undone!", - "payloadType": "str", - "topic": "Restore default settings?", - "topicType": "str", - "x": 930, - "y": 300, - "wires": [ - [ - "e4be21c38b57f560" - ] - ] + "x": 800, + "y": 1940, + "wires": [] }, { - "id": "e4be21c38b57f560", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 1090, - "y": 300, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 1980, "wires": [ [ - "9f30de04ced693d3" + "69516440e3997111", + "f036424d79645761" ] ] }, { - "id": "9f30de04ced693d3", + "id": "d54b85891248ba88", "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 1230, - "y": 300, + "x": 270, + "y": 440, "wires": [ [ - "80bccc884b0be297" + "eefed04c25e3e4d6" ] ] }, { - "id": "80bccc884b0be297", - "type": "link out", - "z": "017bd4e4a428bee5", + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", "name": "", - "mode": "link", - "links": [ - "38783aea9cc317a6" - ], - "x": 1325, - "y": 300, - "wires": [] - }, - { - "id": "34b685aff2080d31", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "boot-cam", - "func": "from OpenScan import load_str\n\ncamera_modules = ('imx519', 'imx219', 'ov5647', 'imx477', 'imx378', 'ov9281', 'imx290a', 'imx290b')\n\npt1 = \"[all]\\n\\ncamera_auto_detect=0\\ngpu_mem=256\\ndtoverlay=vc4-fkms-v3d\\ndtoverlay=\"\npt3 = \",media-controller=1\\n\"\n\nwith open('/boot/config.txt', 'r') as file:\n config = file.read()\n\ncamera = load_str('camera')\nif camera not in camera_modules:\n msg['payload'] = 'no changes'\n return\n\nif camera == 'imx290a':\n camera = 'imx290,clock-frequency=37125000'\nelif camera == 'imx290b':\n camera = 'imx290,clock-frequency=74250000'\n\nconfig_keep = config.split('[all]\\n')[0]\nconfig_new = config_keep + pt1 + camera + pt3\n\nwith open('/boot/config.txt', 'w') as file:\n file.write(config_new)\n\nmsg['topic'] = 'Camera configuration changed'\nmsg['payload'] = 'Please restart the device'\n\nreturn msg", - "outputs": 1, - "x": 680, - "y": 500, + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, "wires": [ [ - "68cba0c530c6def6" + "2aaf7c7f0f0c146f" ] ] }, { - "id": "68cba0c530c6def6", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 830, - "y": 500, + "x": 660, + "y": 440, "wires": [ [] ] }, { - "id": "f304680180a23479", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": true, - "className": "", - "topic": "", - "name": "Info", - "x": 1010, - "y": 120, - "wires": [ - [] - ] + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] }, { - "id": "0d48bb415c584420", + "id": "a12ead9ccf239c19", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadB", - "func": "var file = 'turntable_mode'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 1640, + "x": 190, + "y": 3560, "wires": [ [ - "ce215e159ce7267f" + "d0a1a4947a1137ca" ] ] }, { - "id": "ce215e159ce7267f", + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 520, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Turntable Mode", - "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 2, - "width": 6, - "height": 1, + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", "passthru": true, "decouple": "false", - "topic": "", - "topicType": "str", + "topic": "topic", + "topicType": "msg", "style": "", "onvalue": "true", "onvalueType": "bool", @@ -9788,179 +8386,286 @@ "offcolor": "", "animate": false, "className": "", - "x": 440, - "y": 1640, + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, "wires": [ [ - "f95f528dec31425c" + "1c08a329bd2a669c" ] ] }, { - "id": "f95f528dec31425c", + "id": "bf8e971a52cddab1", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'turntable_mode'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 1640, + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, "wires": [ [] ] }, { - "id": "4ebe5baece5ce9f2", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "preview_resolution", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", "order": 5, - "width": 3, + "width": 6, "height": 1, "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0.5", - "max": "10", - "step": "0.5", + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, "className": "", - "x": 450, - "y": 2280, + "topicType": "msg", + "x": 350, + "y": 3640, "wires": [ [ - "60a415fff23cb55e" + "b5aba11033c5f952" ] ] }, { - "id": "9ed0498cceceedde", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 4, - "width": 3, - "height": 1, - "name": "preview_res", - "label": "Preview Resolution (Mpx)", - "format": "", - "layout": "row-spread", + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, +{ + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", "x": 770, - "y": 2280, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, +{ + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, +{ + "id": "69885a9ce218eb71", + "type": "comment", + "z": "e43a27722b508115", + "name": "Coloritos", + "info": "", + "x": 100, + "y": 3740, "wires": [] }, { - "id": "1efd4a05aee0b86c", + "id": "dc1cde67c3022e6b", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'cam_preview_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data)/1000000;\nreturn msg", + "func": "var file = 'interface_color'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2280, + "x": 190, + "y": 3800, "wires": [ [ - "4ebe5baece5ce9f2" + "0dccca85770c7936" ] ] }, { - "id": "60a415fff23cb55e", + "id": "b63e8246ad14ad9d", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'cam_preview_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload*1000000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "interface-color", + "func": "var file = 'interface_color'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2280, + "x": 540, + "y": 3800, "wires": [ [] ] }, { - "id": "6f3d403e157163e4", + "id": "b7044aa75196b521", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 3", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3800, + "wires": [ + [ + "dc1cde67c3022e6b" + ] + ] + }, + { + "id": "0dccca85770c7936", "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "Camera", + "z": "e43a27722b508115", + "name": "interface_color", "label": "", "tooltip": "", "place": "Select option", - "group": "1f7f7e1e24f5ad9b", - "order": 5, - "width": 4, - "height": 1, + "group": "15edc2ce885dddb3", + "order": 1, + "width": 0, + "height": 0, "passthru": true, "multiple": false, "options": [ { - "label": "Pi Cam v1 - 5mp", - "value": "ov5647", + "label": "Aburrido", + "value": "#097479", "type": "str" }, { - "label": "Pi Cam v2 - 8mp", - "value": "imx219", + "label": "Morado", + "value": "#790974", "type": "str" }, { - "label": "Pi Cam HQ - 12.3mp", - "value": "imx477", + "label": "Berenjena", + "value": "#79093c", "type": "str" }, { - "label": "Arducam IMX519 - 16mp", - "value": "imx519", + "label": "Azul", + "value": "#093c79 ", "type": "str" }, { - "label": "IMX290 a", - "value": "imx290a", - "type": "str" - }, - { - "label": "IMX290 b", - "value": "imx290b", - "type": "str" - }, - { - "label": "IMX378", - "value": "imx378", - "type": "str" - }, - { - "label": "OV9281", - "value": "ov9281", - "type": "str" - }, - { - "label": "DSLR (gphoto)", - "value": "gphoto", - "type": "str" - }, - { - "label": "USB Webcam", - "value": "usb_webcam", - "type": "str" - }, - { - "label": "External Camera", - "value": "external", + "label": "Oliva", + "value": "#747909", "type": "str" } ], @@ -9968,154 +8673,133 @@ "topic": "topic", "topicType": "msg", "className": "", - "x": 400, - "y": 460, + "x": 360, + "y": 3800, "wires": [ [ - "6d68cccec646e0a0", - "4058a31e942e8f95" + "b63e8246ad14ad9d" ] ] }, - { - "id": "c6138801b30f091d", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "model", - "label": "", - "tooltip": "", - "place": "Select option", - "group": "1f7f7e1e24f5ad9b", - "order": 3, - "width": 4, - "height": 1, - "passthru": true, - "multiple": false, - "options": [ - { - "label": "Please Select", - "value": "None", - "type": "str" - }, - { - "label": "OpenScan Mini", - "value": "OSMini", - "type": "str" - }, - { - "label": "OpenScan Classic", - "value": "OSClassic", - "type": "str" - } - ], - "payload": "", - "topic": "topic", - "topicType": "msg", - "className": "", - "x": 390, - "y": 580, +{ + "id": "667950f6671bd1a0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'hostname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 840, "wires": [ [ - "896242c5a7e50fa7" + "b82a1cbefad51cd8" ] ] }, { - "id": "4da67c23c7a543a0", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "1f7f7e1e24f5ad9b", - "order": 4, - "width": 2, - "height": 1, - "name": "", - "label": "Camera", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 840, - "y": 460, - "wires": [] - }, - { - "id": "1fed8676078ea9a7", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "1f7f7e1e24f5ad9b", - "order": 2, - "width": 2, - "height": 1, - "name": "", - "label": "Model", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 730, - "y": 580, - "wires": [] - }, - { - "id": "a4b7eea9a9736b0a", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Update&Info", - "group": "ddbd496e.93a288", - "order": 1, - "width": 6, - "height": 1, - "passthru": false, - "label": "", + "id": "5f32d7e78e368454", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'hostname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "b82a1cbefad51cd8", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "hostname", + "label": "Hostname", "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", - "payloadType": "str", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": 300, "topic": "topic", + "sendOnBlur": true, + "className": "", "topicType": "msg", - "x": 750, - "y": 200, + "x": 360, + "y": 840, "wires": [ [ - "f304680180a23479" + "5f32d7e78e368454" ] ] }, +{ + "id": "5fd155711e29b1b8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Monitoring", + "info": "", + "x": 100, + "y": 3860, + "wires": [] + }, { - "id": "b6e420121e6466e7", + "id": "815702499384f118", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadB", - "func": "var file = 'routine_secondpass'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "func": "var file = 'datadog_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 1600, + "x": 190, + "y": 3920, "wires": [ [ - "ab8d5cfe9190bb5f" + "bfdbdae28bf42ed4" ] ] }, { - "id": "ab8d5cfe9190bb5f", + "id": "464c8495f86daaa7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "datadog_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('datadog_enable'):\n save('datadog_enable', state)\n", + "outputs": 1, + "x": 520, + "y": 3920, + "wires": [ + [] + ] + }, + { + "id": "bfdbdae28bf42ed4", "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Second pass", - "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 3, - "width": 6, - "height": 1, + "z": "e43a27722b508115", + "name": "datadog_enable", + "label": "Enable Datadog", + "tooltip": "Enable Datadog monitoring", + "group": "33aff36289823faa", + "order": 1, + "width": "6", + "height": "1", "passthru": true, "decouple": "false", - "topic": "", - "topicType": "str", + "topic": "topic", + "topicType": "msg", "style": "", "onvalue": "true", "onvalueType": "bool", @@ -10127,206 +8811,261 @@ "offcolor": "", "animate": false, "className": "", - "x": 430, - "y": 1600, + "x": 340, + "y": 3920, + "wires": [ + [ + "464c8495f86daaa7" + ] + ] + }, + { + "id": "f93ce2d26953341f", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "datadog_api_token", + "label": "Datadog Api Token", + "tooltip": "Datadog Api Token", + "group": "33aff36289823faa", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3960, "wires": [ [ - "fa51327f0140b045" + "647641e79884eb87" ] ] }, { - "id": "fa51327f0140b045", + "id": "ee668e39d213070b", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'routine_secondpass'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'datadog_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 1600, + "x": 190, + "y": 3960, "wires": [ - [] + [ + "f93ce2d26953341f" + ] ] }, { - "id": "6841e5a392f0fb4f", + "id": "647641e79884eb87", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'cam_output_downscale'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "z": "e43a27722b508115", + "name": "datadog_api_token", + "func": "var file = 'datadog_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2320, + "x": 550, + "y": 3960, + "wires": [ + [] + ] + }, + { + "id": "ff2dea1ab9cb7776", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 4", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3960, "wires": [ [ - "110216d678fad14f" + "815702499384f118", + "ee668e39d213070b" ] ] }, - { - "id": "110216d678fad14f", - "type": "ui_switch", - "z": "017bd4e4a428bee5", +{ + "id": "a1b81e7fe94ad4e5", + "type": "python3-function", + "z": "e43a27722b508115", "name": "", - "label": "Downscale output", + "func": "import subprocess\nsubprocess.run([\"systemctl\",\"restart\",\"nodered\"])\nreturn msg", + "outputs": 1, + "x": 530, + "y": 3740, + "wires": [ + [] + ] + }, + { + "id": "2f3a3c0e682ae862", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "restart_interface", + "group": "15edc2ce885dddb3", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "Restart Interface", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 6, - "width": 6, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "", - "topicType": "str", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, + "color": "", + "bgcolor": "", "className": "", - "x": 450, - "y": 2320, + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 340, + "y": 3740, "wires": [ [ - "214d548d564f8ba2" + "a1b81e7fe94ad4e5" ] ] }, { - "id": "214d548d564f8ba2", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'cam_output_downscale'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n \nmsg.enabled = msg.payload\nreturn msg", + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'meanwhile'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 2320, + "x": 260, + "y": 140, "wires": [ [ - "1becbff4884b8c1a" + "e23c514008cad1a1" ] ] }, { - "id": "8be1ca844a6caa54", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "output_resolution", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 8, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, "topic": "", - "topicType": "str", - "min": "0.5", - "max": "20", - "step": "0.5", - "className": "", - "x": 450, - "y": 2360, + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, "wires": [ [ - "a6b2c0a0604ccf14" + "4c7fa5b5b27b83a5" ] ] }, { - "id": "9ac09d89d791e953", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 7, - "width": 3, - "height": 1, - "name": "image_res", - "label": "Output Resolution (Mpx)", - "format": "", - "layout": "row-spread", - "className": "", - "x": 770, - "y": 2360, - "wires": [] - }, - { - "id": "1becbff4884b8c1a", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'cam_output_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data)/1000000;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 2360, + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, "wires": [ [ - "8be1ca844a6caa54" + "4ce127c61c3c5966", + "beacc3dc5398fa79" ] ] }, { - "id": "a6b2c0a0604ccf14", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'cam_output_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload*1000000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 2360, + "x": 290, + "y": 220, "wires": [ [] ] }, { - "id": "f358de1e64b491bb", + "id": "beacc3dc5398fa79", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ - "b30d918661392ab3", - "44c598049cd533fd" + "38783aea9cc317a6" ], - "x": 635, - "y": 620, + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "e23c514008cad1a1", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 480, + "y": 140, "wires": [] }, { "id": "b0629875a30ae1d7", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "get update", - "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", "outputs": 2, - "x": 350, - "y": 240, + "x": 390, + "y": 540, "wires": [ [ "1bbe2d769f42c313" @@ -10339,7 +9078,7 @@ { "id": "c7b6d05a62172432", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "ddbd496e.93a288", "order": 3, "width": 0, @@ -10349,19 +9088,19 @@ "format": "{{msg.status}}", "layout": "row-spread", "className": "", - "x": 170, - "y": 100, + "x": 210, + "y": 400, "wires": [] }, { "id": "fefe45404bdb19c4", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "check files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", "outputs": 1, - "x": 510, - "y": 260, + "x": 550, + "y": 560, "wires": [ [ "1bbe2d769f42c313", @@ -10372,13 +9111,14 @@ { "id": "d0104e0163745993", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "links": [ - "960912e90ba5b5bc" + "960912e90ba5b5bc", + "50eeb3e362f9027f" ], - "x": 75, - "y": 140, + "x": 115, + "y": 440, "wires": [ [ "ec30638407332e43", @@ -10390,7 +9130,7 @@ { "id": "ec30638407332e43", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "loadS", "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", "outputs": 1, @@ -10398,8 +9138,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 180, + "x": 210, + "y": 480, "wires": [ [ "2852023f3aa8db10" @@ -10409,7 +9149,7 @@ { "id": "2852023f3aa8db10", "type": "ui_dropdown", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "label": "", "tooltip": "", @@ -10423,21 +9163,26 @@ "options": [ { "label": "stable", - "value": "main", + "value": "stable", "type": "str" }, { "label": "beta", "value": "beta", "type": "str" - } + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" + } ], "payload": "", "topic": "topic", "topicType": "msg", "className": "", - "x": 300, - "y": 180, + "x": 340, + "y": 480, "wires": [ [ "1e10b387ee30c486" @@ -10447,7 +9192,7 @@ { "id": "1e10b387ee30c486", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "write", "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -10455,8 +9200,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 430, - "y": 180, + "x": 470, + "y": 480, "wires": [ [] ] @@ -10464,7 +9209,7 @@ { "id": "274129c51b0b87ef", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "ddbd496e.93a288", "order": 4, "width": 4, @@ -10474,14 +9219,14 @@ "format": "{{msg.payload}}", "layout": "row-spread", "className": "", - "x": 570, - "y": 180, + "x": 610, + "y": 480, "wires": [] }, { "id": "51cd8c8643e6b46a", "type": "ui_switch", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "label": "Auto-check update availability", "tooltip": "", @@ -10504,8 +9249,8 @@ "offcolor": "", "animate": false, "className": "", - "x": 370, - "y": 140, + "x": 410, + "y": 440, "wires": [ [ "1ab4c6b4b232a022" @@ -10515,7 +9260,7 @@ { "id": "38cbf7965d1c1834", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "loadB", "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, @@ -10523,8 +9268,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 140, + "x": 210, + "y": 440, "wires": [ [ "51cd8c8643e6b46a" @@ -10534,7 +9279,7 @@ { "id": "1ab4c6b4b232a022", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "write", "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -10542,8 +9287,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 570, - "y": 140, + "x": 610, + "y": 440, "wires": [ [] ] @@ -10551,7 +9296,7 @@ { "id": "ae92a328af306ebb", "type": "ui_toast", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "position": "dialog", "displayTime": "3", "highlight": "", @@ -10563,8 +9308,8 @@ "className": "", "topic": "", "name": "", - "x": 670, - "y": 260, + "x": 710, + "y": 560, "wires": [ [ "2de63e8e3ae5fb0c", @@ -10575,14 +9320,14 @@ { "id": "cbd0afc4aa7b302a", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "update status", "links": [ "1bbe2d769f42c313", "42061b28cff81f99" ], - "x": 75, - "y": 100, + "x": 115, + "y": 400, "wires": [ [ "c7b6d05a62172432", @@ -10593,20 +9338,20 @@ { "id": "1bbe2d769f42c313", "type": "link out", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ "cbd0afc4aa7b302a" ], - "x": 625, - "y": 220, + "x": 665, + "y": 520, "wires": [] }, { "id": "7cf60615d93e696b", "type": "ui_button", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "group": "ddbd496e.93a288", "order": 7, @@ -10623,8 +9368,8 @@ "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 140, - "y": 260, + "x": 180, + "y": 560, "wires": [ [ "b0629875a30ae1d7" @@ -10634,12 +9379,12 @@ { "id": "2de63e8e3ae5fb0c", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "download files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", "outputs": 1, - "x": 840, - "y": 260, + "x": 880, + "y": 560, "wires": [ [ "42061b28cff81f99", @@ -10650,7 +9395,7 @@ { "id": "929281fef53e09f8", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "msg", "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", "outputs": 1, @@ -10658,8 +9403,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 810, - "y": 220, + "x": 850, + "y": 520, "wires": [ [ "42061b28cff81f99" @@ -10669,20 +9414,20 @@ { "id": "42061b28cff81f99", "type": "link out", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ "cbd0afc4aa7b302a" ], - "x": 955, - "y": 220, + "x": 995, + "y": 520, "wires": [] }, { "id": "49f1ecb29a3f84f4", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "loadB", "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", "outputs": 1, @@ -10690,8 +9435,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 220, + "x": 210, + "y": 520, "wires": [ [ "b0629875a30ae1d7" @@ -10701,26 +9446,28 @@ { "id": "fe3a855fee9e28c6", "type": "link out", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ - "9bb0adbd716ce347" + "9bb0adbd716ce347", + "01c882fcc51b349c" ], - "x": 955, - "y": 260, + "x": 995, + "y": 560, "wires": [] }, { "id": "5e7d5e4335d37794", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "links": [ - "960912e90ba5b5bc" + "960912e90ba5b5bc", + "50eeb3e362f9027f" ], - "x": 55, - "y": 400, + "x": 95, + "y": 700, "wires": [ [ "2bb5fe78e09fec8a" @@ -10730,12 +9477,12 @@ { "id": "2bb5fe78e09fec8a", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "msg", "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", "outputs": 1, - "x": 170, - "y": 400, + "x": 210, + "y": 700, "wires": [ [ "dbc77052ac950624", @@ -10753,7 +9500,7 @@ { "id": "d97c3068ef5fef96", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 2, "width": 0, @@ -10763,14 +9510,14 @@ "format": "{{msg.os}}", "layout": "row-spread", "className": "", - "x": 450, - "y": 440, + "x": 490, + "y": 740, "wires": [] }, { "id": "73a3b828f862312b", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 8, "width": 0, @@ -10780,14 +9527,14 @@ "format": "{{msg.flask}}", "layout": "row-spread", "className": "", - "x": 450, - "y": 480, + "x": 490, + "y": 780, "wires": [] }, { "id": "dbc77052ac950624", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 1, "width": 0, @@ -10797,61 +9544,17 @@ "format": "{{msg.device}}", "layout": "row-spread", "className": "", - "x": 460, - "y": 400, + "x": 500, + "y": 700, "wires": [] }, - { - "id": "4c7fa5b5b27b83a5", - "type": "python3-function", - "z": "c8e7ecb5849edb9a", - "name": "create beta new", - "func": "import json\nimport requests\nimport shutil\n\nscope = 'main'\n#scope = 'beta'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\ndel msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/Arducam.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/Arducam.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/OpenScan.py'\nmsg[scope]['3']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/config.txt'\nmsg[scope]['4']['dst'] = '/boot/config.txt'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/flows.json'\nmsg[scope]['5']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['6'] = {}\nmsg[scope]['6']['src'] = scope + '/settings.js'\nmsg[scope]['6']['dst'] = '/root/.node-red/settings.js'\n\nmsg[scope]['7'] = {}\nmsg[scope]['7']['src'] = 'files/logo.jpg'\nmsg[scope]['7']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", - "outputs": 1, - "x": 300, - "y": 820, - "wires": [ - [ - "50f6fb8adf0249d7" - ] - ] - }, - { - "id": "80175eb8dc6ad009", - "type": "inject", - "z": "c8e7ecb5849edb9a", - "name": "", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "", - "payloadType": "date", - "x": 140, - "y": 820, - "wires": [ - [ - "4c7fa5b5b27b83a5" - ] - ] - }, { "id": "3f42560297fe6978", "type": "ui_template", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "name": "Download LOG", - "order": 9, + "order": 10, "width": 6, "height": 1, "format": "\n
Download error log\n
\n", @@ -10860,8 +9563,8 @@ "resendOnRefresh": false, "templateScope": "local", "className": "", - "x": 140, - "y": 760, + "x": 180, + "y": 1060, "wires": [ [] ] @@ -10869,12 +9572,12 @@ { "id": "c94623ddd9d95f78", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "get update", "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", "outputs": 1, - "x": 170, - "y": 60, + "x": 210, + "y": 360, "wires": [ [] ] @@ -10882,13 +9585,13 @@ { "id": "39a502b38837273d", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "links": [ "1e7457ea9c2c5e09" ], - "x": 205, - "y": 300, + "x": 245, + "y": 600, "wires": [ [ "b0629875a30ae1d7" @@ -10898,7 +9601,7 @@ { "id": "901e31453b2bdff8", "type": "delay", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "pauseType": "delay", "timeout": "10", @@ -10912,8 +9615,8 @@ "drop": false, "allowrate": false, "outputs": 1, - "x": 180, - "y": 440, + "x": 220, + "y": 740, "wires": [ [ "2bb5fe78e09fec8a" @@ -10923,7 +9626,7 @@ { "id": "f983854748ee4763", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 3, "width": 0, @@ -10933,14 +9636,14 @@ "format": "{{msg.osdate}}", "layout": "row-spread", "className": "", - "x": 450, - "y": 520, + "x": 490, + "y": 820, "wires": [] }, { "id": "5347c7c517f5e8c7", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 4, "width": 0, @@ -10950,14 +9653,14 @@ "format": "{{msg.temp}}", "layout": "row-spread", "className": "", - "x": 470, - "y": 560, + "x": 510, + "y": 860, "wires": [] }, { "id": "3a5016f7003cd72c", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 5, "width": 0, @@ -10967,14 +9670,14 @@ "format": "{{msg.cpu}}", "layout": "row-spread", "className": "", - "x": 480, - "y": 600, + "x": 520, + "y": 900, "wires": [] }, { "id": "6d720c4a4ecd9475", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 6, "width": 0, @@ -10984,14 +9687,14 @@ "format": "{{msg.swap}}", "layout": "row-spread", "className": "", - "x": 480, - "y": 640, + "x": 520, + "y": 940, "wires": [] }, { "id": "6438b7d060a70d81", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 7, "width": 0, @@ -11001,70 +9704,14 @@ "format": "{{msg.diskspace}}", "layout": "row-spread", "className": "", - "x": 470, - "y": 680, - "wires": [] - }, - { - "id": "d7362e6e0ec7bdaa", - "type": "inject", - "z": "c8e7ecb5849edb9a", - "name": "", - "props": [ - { - "p": "overwrite", - "v": "true", - "vt": "bool" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "x": 130, - "y": 900, - "wires": [ - [ - "4ce127c61c3c5966", - "beacc3dc5398fa79" - ] - ] - }, - { - "id": "4ce127c61c3c5966", - "type": "python3-function", - "z": "c8e7ecb5849edb9a", - "name": "prepare image creation", - "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", - "outputs": 1, - "x": 330, - "y": 900, - "wires": [ - [] - ] - }, - { - "id": "beacc3dc5398fa79", - "type": "link out", - "z": "c8e7ecb5849edb9a", - "name": "", - "mode": "link", - "links": [ - "38783aea9cc317a6" - ], - "x": 235, - "y": 940, + "x": 510, + "y": 980, "wires": [] }, { "id": "8d012912f302be85", "type": "ui_button", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "group": "ddbd496e.93a288", "order": 8, @@ -11081,8 +9728,8 @@ "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 170, - "y": 340, + "x": 210, + "y": 640, "wires": [ [ "5242607a723cc628" @@ -11092,12 +9739,12 @@ { "id": "5242607a723cc628", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "Changelog", - "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/OpenScan-org/OpenScan-Doc/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", "outputs": 1, - "x": 390, - "y": 340, + "x": 430, + "y": 640, "wires": [ [ "573722197b15bf84" @@ -11107,7 +9754,7 @@ { "id": "573722197b15bf84", "type": "ui_toast", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "position": "dialog", "displayTime": "3", "highlight": "", @@ -11119,27 +9766,51 @@ "className": "", "topic": "", "name": "", - "x": 570, - "y": 340, + "x": 610, + "y": 640, "wires": [ [] ] }, { - "id": "50f6fb8adf0249d7", - "type": "debug", - "z": "c8e7ecb5849edb9a", + "id": "cde61b7de9eeaba7", + "type": "ui_button", + "z": "a5557543ccff5889", "name": "", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 570, - "y": 820, - "wires": [] + "group": "3ce32450.e0cffc", + "order": 9, + "width": 0, + "height": 0, + "passthru": false, + "label": "Expand Root", + "tooltip": "Sets the maximum space your SD card admits", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "expand", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 510, + "y": 1020, + "wires": [ + [ + "eab36487d201f867" + ] + ] + }, + { + "id": "eab36487d201f867", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "", + "func": "import subprocess\nsubprocess.run([\"raspi-config\",\"--expand-rootfs\"])\nreturn msg", + "outputs": 1, + "x": 690, + "y": 1020, + "wires": [ + [] + ] } ] \ No newline at end of file diff --git a/update/beta/settings.js b/update/beta/settings.js index 834f457..357b02b 100644 --- a/update/beta/settings.js +++ b/update/beta/settings.js @@ -1,5 +1,5 @@ /** - * Node-RED Settings created at Mon, 24 Jan 2022 08:17:31 GMT + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT * * It can contain any valid JavaScript code that will get run when Node-RED * is started. @@ -19,6 +19,7 @@ * - Node Settings * **/ +process.env.HOSTNAME = require('os').hostname(); module.exports = { @@ -54,7 +55,8 @@ module.exports = { * property can be used */ //userDir: '/home/nol/.node-red/', - userDir: '/home/pi/OpenScan/settings/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + /** Node-RED scans the `nodes` directory in the userDir to find local node files. * The following property can be used to specify an additional directory to scan. */ @@ -137,11 +139,12 @@ module.exports = { * - httpNodeCors * - httpNodeMiddleware * - httpStatic + * - httpStaticRoot ******************************************************************************/ /** the tcp port that the Node-RED web server is listening on */ -// uiPort: process.env.PORT || 1880, -uiPort: process.env.PORT || 80, + uiPort: process.env.PORT || 80, + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. * To listen on all IPv6 addresses, set uiHost to "::", * The following property can be used to listen on a specific interface. For @@ -164,8 +167,8 @@ uiPort: process.env.PORT || 80, * The following property can be used to specify a different root path. * If set to false, this is disabled. */ - //httpAdminRoot: '/admin', -httpAdminRoot: '/editor', + httpAdminRoot: '/editor', + /** The following property can be used to add a custom middleware function * in front of all admin http routes. For example, to set custom http * headers. It can be a single function or an array of middleware functions. @@ -218,9 +221,28 @@ httpAdminRoot: '/editor', /** When httpAdminRoot is used to move the UI to a different root path, the * following property can be used to identify a directory of static content * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot */ - //httpStatic: '/home/nol/node-red-static/', -httpStatic: '/home/pi/OpenScan/', + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + /******************************************************************************* * Runtime Settings * - lang @@ -348,9 +370,9 @@ httpStatic: '/home/pi/OpenScan/', }, codeEditor: { /** Select the text editor component used by the editor. - * Defaults to "ace", but can be set to "ace" or "monaco" + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired */ - lib: "ace", + lib: "monaco", options: { /** The follow options only apply if the editor is set to "monaco" * @@ -360,7 +382,7 @@ httpStatic: '/home/pi/OpenScan/', */ theme: "vs", /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. - * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandaloneeditorconstructionoptions.html + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html */ //fontSize: 14, //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", @@ -405,13 +427,14 @@ httpStatic: '/home/pi/OpenScan/', * will allow the `os` module to be accessed in a Function node using: * global.get("os") */ - functionGlobalContext: { - os:require('os'), - path:require('path'), - fs:require('fs'), - -}, - +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, /** The maximum number of messages nodes will buffer internally as part of their * operation. This applies across a range of nodes that operate on message sequences. * defaults to no limit. A value of 0 also means no limit is applied. @@ -425,8 +448,8 @@ httpStatic: '/home/pi/OpenScan/', * middleware:{function or array}, (req,res,next) - http middleware * ioMiddleware:{function or array}, (socket,next) - socket.io middleware */ - //ui: { path: "ui" }, -ui: { path: "" }, + ui: { path: "" }, + /** Colourise the console output of the debug node */ //debugUseColors: true, diff --git a/update/betaArdu/Arducam.py b/update/betaArdu/Arducam.py deleted file mode 100644 index 941e07b..0000000 --- a/update/betaArdu/Arducam.py +++ /dev/null @@ -1,202 +0,0 @@ -import time -import os - -try: - import v4l2 -except Exception as e: - print(e) - print("Try to install v4l2-fix") - try: - from pip import main as pipmain - except ImportError: - from pip._internal import main as pipmain - pipmain(['install', 'v4l2-fix']) - print("\nTry to run the focus program again.") - exit(0) - -import fcntl -import errno - -# # Type -# v4l2.V4L2_CTRL_TYPE_INTEGER -# v4l2.V4L2_CTRL_TYPE_BOOLEAN -# v4l2.V4L2_CTRL_TYPE_MENU -# v4l2.V4L2_CTRL_TYPE_BUTTON -# v4l2.V4L2_CTRL_TYPE_INTEGER64 -# v4l2.V4L2_CTRL_TYPE_CTRL_CLASS -# # Flags -# v4l2.V4L2_CTRL_FLAG_DISABLED -# v4l2.V4L2_CTRL_FLAG_GRABBED -# v4l2.V4L2_CTRL_FLAG_READ_ONLY -# v4l2.V4L2_CTRL_FLAG_UPDATE -# v4l2.V4L2_CTRL_FLAG_INACTIVE -# v4l2.V4L2_CTRL_FLAG_SLIDER - -def assert_valid_queryctrl(queryctrl): - return queryctrl.type & ( - v4l2.V4L2_CTRL_TYPE_INTEGER - | v4l2.V4L2_CTRL_TYPE_BOOLEAN - | v4l2.V4L2_CTRL_TYPE_MENU - | v4l2.V4L2_CTRL_TYPE_BUTTON - | v4l2.V4L2_CTRL_TYPE_INTEGER64 - | v4l2.V4L2_CTRL_TYPE_CTRL_CLASS - | 7 - | 8 - | 9 - ) and queryctrl.flags & ( - v4l2.V4L2_CTRL_FLAG_DISABLED - | v4l2.V4L2_CTRL_FLAG_GRABBED - | v4l2.V4L2_CTRL_FLAG_READ_ONLY - | v4l2.V4L2_CTRL_FLAG_UPDATE - | v4l2.V4L2_CTRL_FLAG_INACTIVE - | v4l2.V4L2_CTRL_FLAG_SLIDER - ) - -def get_device_controls_menu(fd, queryctrl): - querymenu = v4l2.v4l2_querymenu(queryctrl.id, queryctrl.minimum) - while querymenu.index <= queryctrl.maximum: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYMENU, querymenu) - yield querymenu - querymenu.index += 1 - -def get_device_controls_by_class(fd, control_class): - # enumeration by control class - queryctrl = v4l2.v4l2_queryctrl(control_class | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - while True: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - except IOError as e: - assert e.errno == errno.EINVAL - break - if v4l2.V4L2_CTRL_ID2CLASS(queryctrl.id) != control_class: - break - yield queryctrl - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - -def getdict(struct): - val = dict((field, getattr(struct, field)) for field, _ in struct._fields_) - val.pop("reserved") - return val - -def get_device_controls(fd): - # original enumeration method - queryctrl = v4l2.v4l2_queryctrl(v4l2.V4L2_CID_BASE) - while queryctrl.id < v4l2.V4L2_CID_LASTP1: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - print(queryctrl.name) - except IOError as e: - # this predefined control is not supported by this device - assert e.errno == errno.EINVAL - queryctrl.id += 1 - continue - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id + 1) - -def get_ctrls(vd): - ctrls = [] - # enumeration by control class - for class_ in (v4l2.V4L2_CTRL_CLASS_USER, v4l2.V4L2_CTRL_CLASS_MPEG, v4l2.V4L2_CTRL_CLASS_CAMERA): - for queryctrl in get_device_controls_by_class(vd, class_): - ctrl = getdict(queryctrl) - if queryctrl.type == v4l2.V4L2_CTRL_TYPE_MENU: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - # print(querymenu.name) - ctrl["menu"].append(querymenu.name) - - if queryctrl.type == 9: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - ctrl["menu"].append(querymenu.index) - ctrls.append(ctrl) - return ctrls - -def set_ctrl(vd, id, value): - ctrl = v4l2.v4l2_control() - ctrl.id = id - ctrl.value = value - try: - fcntl.ioctl(vd, v4l2.VIDIOC_S_CTRL, ctrl) - except IOError as e: - print(e) - -def get_ctrl(vd, id): - ctrl = v4l2.v4l2_control() - ctrl.id = id - try: - fcntl.ioctl(vd, v4l2.VIDIOC_G_CTRL, ctrl) - except IOError as e: - print(e) - return None - return ctrl.value - - -class Focuser: - FOCUS_ID = 0x009a090a - dev = None - - def __init__(self, dev=0): - self.focus_value = 0 - self.dev = dev - - if type(dev) == int or (type(dev) == str and dev.isnumeric()): - self.dev = "/dev/video{}".format(dev) - - self.fd = open(self.dev, 'r') - self.ctrls = get_ctrls(self.fd) - self.hasFocus = False - for ctrl in self.ctrls: - if ctrl['id'] == Focuser.FOCUS_ID: - self.hasFocus = True - self.opts[Focuser.OPT_FOCUS]["MIN_VALUE"] = ctrl['minimum'] - self.opts[Focuser.OPT_FOCUS]["MAX_VALUE"] = ctrl['maximum'] - self.opts[Focuser.OPT_FOCUS]["DEF_VALUE"] = ctrl['default'] - self.focus_value = get_ctrl(self.fd, Focuser.FOCUS_ID) - - if not self.hasFocus: - raise RuntimeError("Device {} has no focus_absolute control.".format(self.dev)) - - def read(self): - return self.focus_value - - def write(self, value): - self.focus_value = value - # os.system("v4l2-ctl -d {} -c focus_absolute={}".format(self.dev, value)) - set_ctrl(self.fd, Focuser.FOCUS_ID, value) - - OPT_BASE = 0x1000 - OPT_FOCUS = OPT_BASE | 0x01 - OPT_ZOOM = OPT_BASE | 0x02 - OPT_MOTOR_X = OPT_BASE | 0x03 - OPT_MOTOR_Y = OPT_BASE | 0x04 - OPT_IRCUT = OPT_BASE | 0x05 - opts = { - OPT_FOCUS : { - "MIN_VALUE": 0, - "MAX_VALUE": 1000, - "DEF_VALUE": 0, - }, - } - def reset(self,opt,flag = 1): - info = self.opts[opt] - if info == None or info["DEF_VALUE"] == None: - return - self.set(opt,info["DEF_VALUE"]) - - def get(self,opt,flag = 0): - info = self.opts[opt] - return self.read() - - def set(self,opt,value,flag = 1): - info = self.opts[opt] - if value > info["MAX_VALUE"]: - value = info["MAX_VALUE"] - elif value < info["MIN_VALUE"]: - value = info["MIN_VALUE"] - self.write(value) - print("write: {}".format(value)) - - def __del__(self): - self.fd.close() - -pass diff --git a/update/main/Arducam.py b/update/main/Arducam.py deleted file mode 100644 index 941e07b..0000000 --- a/update/main/Arducam.py +++ /dev/null @@ -1,202 +0,0 @@ -import time -import os - -try: - import v4l2 -except Exception as e: - print(e) - print("Try to install v4l2-fix") - try: - from pip import main as pipmain - except ImportError: - from pip._internal import main as pipmain - pipmain(['install', 'v4l2-fix']) - print("\nTry to run the focus program again.") - exit(0) - -import fcntl -import errno - -# # Type -# v4l2.V4L2_CTRL_TYPE_INTEGER -# v4l2.V4L2_CTRL_TYPE_BOOLEAN -# v4l2.V4L2_CTRL_TYPE_MENU -# v4l2.V4L2_CTRL_TYPE_BUTTON -# v4l2.V4L2_CTRL_TYPE_INTEGER64 -# v4l2.V4L2_CTRL_TYPE_CTRL_CLASS -# # Flags -# v4l2.V4L2_CTRL_FLAG_DISABLED -# v4l2.V4L2_CTRL_FLAG_GRABBED -# v4l2.V4L2_CTRL_FLAG_READ_ONLY -# v4l2.V4L2_CTRL_FLAG_UPDATE -# v4l2.V4L2_CTRL_FLAG_INACTIVE -# v4l2.V4L2_CTRL_FLAG_SLIDER - -def assert_valid_queryctrl(queryctrl): - return queryctrl.type & ( - v4l2.V4L2_CTRL_TYPE_INTEGER - | v4l2.V4L2_CTRL_TYPE_BOOLEAN - | v4l2.V4L2_CTRL_TYPE_MENU - | v4l2.V4L2_CTRL_TYPE_BUTTON - | v4l2.V4L2_CTRL_TYPE_INTEGER64 - | v4l2.V4L2_CTRL_TYPE_CTRL_CLASS - | 7 - | 8 - | 9 - ) and queryctrl.flags & ( - v4l2.V4L2_CTRL_FLAG_DISABLED - | v4l2.V4L2_CTRL_FLAG_GRABBED - | v4l2.V4L2_CTRL_FLAG_READ_ONLY - | v4l2.V4L2_CTRL_FLAG_UPDATE - | v4l2.V4L2_CTRL_FLAG_INACTIVE - | v4l2.V4L2_CTRL_FLAG_SLIDER - ) - -def get_device_controls_menu(fd, queryctrl): - querymenu = v4l2.v4l2_querymenu(queryctrl.id, queryctrl.minimum) - while querymenu.index <= queryctrl.maximum: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYMENU, querymenu) - yield querymenu - querymenu.index += 1 - -def get_device_controls_by_class(fd, control_class): - # enumeration by control class - queryctrl = v4l2.v4l2_queryctrl(control_class | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - while True: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - except IOError as e: - assert e.errno == errno.EINVAL - break - if v4l2.V4L2_CTRL_ID2CLASS(queryctrl.id) != control_class: - break - yield queryctrl - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - -def getdict(struct): - val = dict((field, getattr(struct, field)) for field, _ in struct._fields_) - val.pop("reserved") - return val - -def get_device_controls(fd): - # original enumeration method - queryctrl = v4l2.v4l2_queryctrl(v4l2.V4L2_CID_BASE) - while queryctrl.id < v4l2.V4L2_CID_LASTP1: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - print(queryctrl.name) - except IOError as e: - # this predefined control is not supported by this device - assert e.errno == errno.EINVAL - queryctrl.id += 1 - continue - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id + 1) - -def get_ctrls(vd): - ctrls = [] - # enumeration by control class - for class_ in (v4l2.V4L2_CTRL_CLASS_USER, v4l2.V4L2_CTRL_CLASS_MPEG, v4l2.V4L2_CTRL_CLASS_CAMERA): - for queryctrl in get_device_controls_by_class(vd, class_): - ctrl = getdict(queryctrl) - if queryctrl.type == v4l2.V4L2_CTRL_TYPE_MENU: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - # print(querymenu.name) - ctrl["menu"].append(querymenu.name) - - if queryctrl.type == 9: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - ctrl["menu"].append(querymenu.index) - ctrls.append(ctrl) - return ctrls - -def set_ctrl(vd, id, value): - ctrl = v4l2.v4l2_control() - ctrl.id = id - ctrl.value = value - try: - fcntl.ioctl(vd, v4l2.VIDIOC_S_CTRL, ctrl) - except IOError as e: - print(e) - -def get_ctrl(vd, id): - ctrl = v4l2.v4l2_control() - ctrl.id = id - try: - fcntl.ioctl(vd, v4l2.VIDIOC_G_CTRL, ctrl) - except IOError as e: - print(e) - return None - return ctrl.value - - -class Focuser: - FOCUS_ID = 0x009a090a - dev = None - - def __init__(self, dev=0): - self.focus_value = 0 - self.dev = dev - - if type(dev) == int or (type(dev) == str and dev.isnumeric()): - self.dev = "/dev/video{}".format(dev) - - self.fd = open(self.dev, 'r') - self.ctrls = get_ctrls(self.fd) - self.hasFocus = False - for ctrl in self.ctrls: - if ctrl['id'] == Focuser.FOCUS_ID: - self.hasFocus = True - self.opts[Focuser.OPT_FOCUS]["MIN_VALUE"] = ctrl['minimum'] - self.opts[Focuser.OPT_FOCUS]["MAX_VALUE"] = ctrl['maximum'] - self.opts[Focuser.OPT_FOCUS]["DEF_VALUE"] = ctrl['default'] - self.focus_value = get_ctrl(self.fd, Focuser.FOCUS_ID) - - if not self.hasFocus: - raise RuntimeError("Device {} has no focus_absolute control.".format(self.dev)) - - def read(self): - return self.focus_value - - def write(self, value): - self.focus_value = value - # os.system("v4l2-ctl -d {} -c focus_absolute={}".format(self.dev, value)) - set_ctrl(self.fd, Focuser.FOCUS_ID, value) - - OPT_BASE = 0x1000 - OPT_FOCUS = OPT_BASE | 0x01 - OPT_ZOOM = OPT_BASE | 0x02 - OPT_MOTOR_X = OPT_BASE | 0x03 - OPT_MOTOR_Y = OPT_BASE | 0x04 - OPT_IRCUT = OPT_BASE | 0x05 - opts = { - OPT_FOCUS : { - "MIN_VALUE": 0, - "MAX_VALUE": 1000, - "DEF_VALUE": 0, - }, - } - def reset(self,opt,flag = 1): - info = self.opts[opt] - if info == None or info["DEF_VALUE"] == None: - return - self.set(opt,info["DEF_VALUE"]) - - def get(self,opt,flag = 0): - info = self.opts[opt] - return self.read() - - def set(self,opt,value,flag = 1): - info = self.opts[opt] - if value > info["MAX_VALUE"]: - value = info["MAX_VALUE"] - elif value < info["MIN_VALUE"]: - value = info["MIN_VALUE"] - self.write(value) - print("write: {}".format(value)) - - def __del__(self): - self.fd.close() - -pass diff --git a/update/main/fla.py b/update/main/fla.py deleted file mode 100644 index 5fe4649..0000000 --- a/update/main/fla.py +++ /dev/null @@ -1,149 +0,0 @@ -from flask import Flask, make_response, jsonify, request, abort -from PIL import Image -import gphoto2 as gp -from time import sleep, time -import shutil -from OpenScan import load_int, load_float, load_bool, ringlight -import RPi.GPIO as GPIO -from math import sqrt -import os - -GPIO.setwarnings(False) -GPIO.setmode(GPIO.BCM) - -app = Flask(__name__) - -basedir = '/home/pi/OpenScan/' -timer = time() - -################################################################################################################### -@app.route('/shutdown', methods=['get']) -def shutdown(): - delay = 0.1 - ringlight(2,False) - - for i in range (5): - ringlight(1,True) - sleep(delay) - ringlight(1,False) - sleep(delay) - os.system('shutdown -h now') -################################################################################################################### -@app.route('/reboot', methods=['get']) -def reboot(): - delay = 0.1 - ringlight(2,False) - - for i in range (5): - ringlight(1,True) - sleep(delay) - ringlight(1,False) - sleep(delay) - - os.system('reboot -h') -################################################################################################################### -@app.route('/ping', methods=['get']) -def ping(): - global timer - cmd = str(request.args.get('cmd')) - if cmd == 'set': - timer = time() - inactive = time() - timer - return ({'inactive':inactive}, 200) -################################################################################################################### -@app.route('/gphoto_init', methods=['get']) -def gphoto_init(): - global camera - camera = gp.Camera() - camera.init() - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_preview', methods=['get']) -def gphoto_preview(): - filepath = str(request.args.get('filepath')) - camera_file = gp.gp_camera_capture_preview(camera)[1] - target = basedir + filepath - camera_file.save(target) - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_capture', methods=['get']) -def gphoto_capture(): - filepath = str(request.args.get('filepath')) - file_path = camera.capture(gp.GP_CAPTURE_IMAGE) - camera_file = camera.file_get(file_path.folder, file_path.name, gp.GP_FILE_TYPE_NORMAL) - camera_file.save(basedir + filepath) - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_test', methods=['get']) -def gphoto_test(): - text = camera.get_summary() - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_exit', methods=['get']) -def gphoto_exit(): - global camera - camera.exit() - return ({}, 200) -################################################################################################################### -@app.route('/crop', methods=['get']) -def crop(): - output_downscale = load_bool('cam_output_downscale') - output_resolution = load_int('cam_output_resolution') - preview_resolution = load_int('cam_preview_resolution') - filepath_in = basedir + str(request.args.get('filepath_in')) - filepath_out = basedir + str(request.args.get('filepath_out')) - cropx = int(request.args.get('cropx'))/200 - cropy = int(request.args.get('cropy'))/200 - rotation = int(request.args.get('rotation')) - preview = str(request.args.get('preview')) - downscale = 1 - - with Image.open(filepath_in) as img: - w,h = img.size - if cropx != 0 or cropy != 0: - img = img.crop((w*cropx, h*cropy, w * (1-cropx), h * (1-cropy))) - if rotation == 90: - img = img.transpose(Image.ROTATE_90) - elif rotation == 180: - img= img.transpose(Image.ROTATE_180) - elif rotation == 270: - img= img.transpose(Image.ROTATE_270) - - if preview == "True": - w,h = img.size - factor = (w*h)/preview_resolution - if factor > 1: - img = img.resize((int(w/sqrt(factor)),int(h/sqrt(factor))),Image.ANTIALIAS) - - elif output_downscale == True: - w,h = img.size - factor = (w*h)/output_resolution - if factor > 1: - img = img.resize((int(w/sqrt(factor)),int(h/sqrt(factor))),Image.ANTIALIAS) - - img.save(filepath_out, quality=95, subsampling=0) - - return ({}, 200) - -################################################################################################################### -@app.route('/external_capture', methods=['get']) -def external_capture(): - pin = load_int('pin_external') - delay_before = load_float('cam_delay_before') - timeout = load_float('cam_timeout')/1000 - delay_after = load_float('cam_delay_after') - GPIO.setup(pin, GPIO.OUT) - GPIO.output(pin, GPIO.LOW) - sleep(delay_before) - GPIO.output(pin, GPIO.HIGH) - sleep(timeout) - GPIO.output(pin, GPIO.LOW) - sleep(delay_after) - return ({}, 200) - - - - -if __name__ == '__main__': -# app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) - app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) diff --git a/update/meanwhile/OpenScan.py b/update/meanwhile/OpenScan.py new file mode 100644 index 0000000..9cc5e77 --- /dev/null +++ b/update/meanwhile/OpenScan.py @@ -0,0 +1,318 @@ +basepath = '/home/pi/OpenScan/' +from os.path import isfile +import os + +def load_bool(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + if value == '1' or value == 'True' or value =='true': + value = True + else: + value = False + return value + +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + + return True + + +def load_str(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + return value + +def load_int(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = int(file.read().replace('\n','')) + return value + +def load_float(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = float(file.read().replace('\n','')) + return value + +def save(name, value): + filename = basepath+'settings/'+name + with open(filename, 'w+') as file: + file.write(str(value)) + return + +def OpenScanCloud(cmd, msg): + from requests import get + osc_user = 'openscan' + osc_pw = 'free' + osc_server = 'http://openscanfeedback.dnsuser.de:1334/' + + try: + r = get(osc_server + cmd, auth=(osc_user, osc_pw), params=msg) + except: + r = type('obj', (object,), {'status_code' : 404, 'text':None}) + return r + +def camera(cmd, msg = {}): + from requests import get + flask = 'http://127.0.0.1:1312/' + try: + r = get(flask + cmd, params=msg) + return r.status_code + except: + return 400 + +def motorrun(motor,angle,ES_enable=False): + #motor can be "rotor", "tt" or "extra" + import RPi.GPIO as GPIO + from time import sleep + from math import cos + msg = {'cmd':'set'} + + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + + spr = load_int(motor + '_stepsperrotation') + dirpin = load_int('pin_' + motor + '_dir') + steppin = load_int('pin_' + motor +'_step') + ES_pin = load_int('pin_' + motor + '_endstop') + ES_pushed = load_bool(motor + '_endstop_pushed') + dir = load_int(motor + '_dir') + ramp = load_int(motor + '_accramp') + acc = load_float(motor + '_acc') + delay_init = load_float(motor + '_delay') + delay = delay_init + + step_count=int(angle*spr/360) * dir + GPIO.setup(dirpin, GPIO.OUT) + GPIO.setup(steppin, GPIO.OUT) + GPIO.setup(ES_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP) + + if (step_count>0): + GPIO.output(dirpin, GPIO.HIGH) + if(step_count<0): + GPIO.output(dirpin, GPIO.LOW) + step_count=-step_count + + for x in range(step_count): + if ES_enable == True and GPIO.input(ES_pin) == ES_pushed and (motor == "rotor" and GPIO.input(dirpin) == False): + i = 0 + while i <= 10: + if GPIO.input(ES_pin) != ES_pushed: + i = 11 + if i == 10: + return + i = i + 1 + + GPIO.output(steppin, GPIO.HIGH) + if x<=ramp and x<=step_count/2: + delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) + #delay=delay_init+(ramp-x)*(delay_init)/acc + elif step_count-x<=ramp and x>step_count/2: + delay = delay_init * (1-1/acc*cos(1*(ramp+x-step_count)/ramp)+1/acc) + #delay=delay_init+(ramp-step_count+x)*(delay_init)/acc + else: + delay = delay_init + sleep(delay) + GPIO.output(steppin, GPIO.LOW) + sleep(delay) + +def ringlight(number,state): + import RPi.GPIO as GPIO + msg = {'cmd':'set'} + pin = load_int('pin_ringlight' + str(number)) + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + GPIO.setup(pin, GPIO.OUT) + GPIO.output(pin, state) + +def take_photo(file): + from os import system + filepath = basepath + file + + model=load_str('model') + + + + shutter = str(load_int('cam_shutter')) + saturation = load_str('cam_saturation') + contrast = load_str('cam_contrast') + awbg_red = load_str('cam_awbg_red') + awbg_blue = load_str('cam_awbg_blue') + gain = load_str('cam_gain') + quality = load_int('cam_jpeg_quality') + filepath2 = '/home/pi/OpenScan/tmp/tmp.jpg' + #width = load_str('cam_resx') + #height = load_str('cam_resy') + timeout = load_str('cam_timeout') + cropx = load_int('cam_cropx')/200 + cropy = load_int('cam_cropy')/200 + rotation = load_int('cam_rotation') + AF = load_bool('cam_AFmode') + camera = load_str('camera') + + + if camera == 'imx519' and AF == True: + autofocus = ' --autofocus ' + else: + autofocus = '' + + if camera == "usb_webcam": + cmd = 'fswebcam -i 0 -r "1280x720" -F 5 --no-banner --jpeg 95 --save ' + filepath2 + else: + cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + ' >/dev/null 2>&1' + # cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + + system(cmd) + return cmd + +def get_points(samples=1): + from math import pi, sqrt, acos, atan2, cos, sin + + points = [] + phi = pi * (3. - sqrt(5.)) + for i in range(int(samples)): + y = 1 - (i / float(samples - 1)) * 2 + radius = sqrt(1 - y * y) + theta = phi * i + x = cos(theta) * radius + z = sin(theta) * radius + r=sqrt(x*x+y*y+z*z) + theta_neu=acos(z/r)*180/pi + phi_neu=atan2(y,x)*180/pi + points.append((theta_neu-90,phi_neu)) + points.sort() + return points + +def create_coordinates(angle_min, angle_max,point_count): + point_count_final=point_count + if angle_max < angle_min: + a = angle_min + angle_min = angle_max + angle_max = a + point_count=point_count*90/(angle_max-angle_min) + actual_points=0 + while actual_pointsangle_min and x20: + point_count=point_count+3 + else: + point_count=point_count+1 + return filtered + + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/meanwhile/config.txt b/update/meanwhile/config.txt new file mode 100755 index 0000000..6d55082 --- /dev/null +++ b/update/meanwhile/config.txt @@ -0,0 +1,34 @@ +# For more options and information see +# http://rpf.io/configtxt +# Some settings may impact device functionality. See link above for details + +# Additional overlays and parameters are documented /boot/overlays/README + +# Automatically load overlays for detected cameras +camera_auto_detect=1 + +# Automatically load overlays for detected DSI displays +display_auto_detect=1 + +# Enable DRM VC4 V3D driver +dtoverlay=vc4-kms-v3d +max_framebuffers=1 + +# Disable compensation for displays with overscan +disable_overscan=1 + +[cm4] +# Enable host mode on the 2711 built-in XHCI USB controller. +# This line should be removed if the legacy DWC2 controller is required +# (e.g. for USB device mode) or if USB support is not required. +otg_mode=1 + +[pi4] +# Run as fast as firmware / board allows +arm_boost=1 +dtoverlay=imx519,cma-512 + +[all] +camera_auto_detect=0 +gpu_mem=256 +dtoverlay=imx519 diff --git a/update/betaArdu/fla.py b/update/meanwhile/fla.py similarity index 89% rename from update/betaArdu/fla.py rename to update/meanwhile/fla.py index 7fd27dd..57f4660 100644 --- a/update/betaArdu/fla.py +++ b/update/meanwhile/fla.py @@ -1,4 +1,4 @@ -from flask import Flask, make_response, jsonify, request, abort +from flask import Flask, make_response, jsonify, request, abort, redirect from picamera2 import Picamera2 from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont from time import sleep, time @@ -11,6 +11,7 @@ from skimage import io, feature, color, transform import numpy as np from scipy import ndimage +import socket GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) @@ -20,6 +21,7 @@ basedir = '/home/pi/OpenScan/' timer = time() cam_mode = 0 +hostname = socket.gethostname().split(":") def overlay_mask(image, mask_image): # Ensure image is in RGB mode @@ -69,28 +71,44 @@ def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilatio ################################################################################################################### @app.route('/shutdown', methods=['get']) def shutdown(): - delay = 0.1 - ringlight(2,False) - - for i in range (5): - ringlight(1,True) - sleep(delay) - ringlight(1,False) - sleep(delay) - os.system('shutdown -h now') + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + f = open("/home/pi/OpenScan/settings/session_token", "r") + session_token = (f.readline())[:20] + if shutdown_token == session_token: + + delay = 0.1 + ringlight(2,False) + + for i in range (5): + ringlight(1,True) + sleep(delay) + ringlight(1,False) + sleep(delay) + os.system('shutdown -h now') + + else: + return redirect("http://" + hostname, code=302) ################################################################################################################### @app.route('/reboot', methods=['get']) def reboot(): - delay = 0.1 - ringlight(2,False) - - for i in range (5): - ringlight(1,True) - sleep(delay) - ringlight(1,False) - sleep(delay) - - os.system('reboot -h') + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + f = open("/home/pi/OpenScan/settings/session_token", "r") + session_token = (f.readline())[:20] + if shutdown_token == session_token: + delay = 0.1 + ringlight(2,False) + + for i in range (5): + ringlight(1,True) + sleep(delay) + ringlight(1,False) + sleep(delay) + + os.system('reboot -h') + else: + return redirect("http://" + hostname, code=302) ################################################################################################################### def plot_orb_keypoints(pil_image): @@ -323,6 +341,11 @@ def picam2_af(): picam2.set_controls({"AfMode": 1 ,"AfTrigger": 0}) # --> wait 3-5s return ({}, 200) +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + if __name__ == '__main__': # app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) diff --git a/update/beta/flows.json b/update/meanwhile/flows.json.tmpl similarity index 59% rename from update/beta/flows.json rename to update/meanwhile/flows.json.tmpl index f16c4fb..81f4f3c 100644 --- a/update/beta/flows.json +++ b/update/meanwhile/flows.json.tmpl @@ -1,55 +1,66 @@ [ { - "id": "829d803b6033a693", + "id": "e6f4d02efb300ea9", "type": "tab", - "label": "HOME", + "label": "Init", "disabled": false, "info": "", "env": [] }, { - "id": "1613373abaf77a2c", + "id": "481edaf6db5a7a54", "type": "tab", - "label": "SCAN", + "label": "Scan", "disabled": false, "info": "", "env": [] }, { - "id": "4981d84ef1a366d1", + "id": "80a3942785a26c29", "type": "tab", - "label": "Files&Cloud", + "label": "Files", "disabled": false, "info": "", "env": [] }, { - "id": "017bd4e4a428bee5", + "id": "e43a27722b508115", "type": "tab", - "label": "SETTINGS", + "label": "Settings", "disabled": false, "info": "", "env": [] }, { - "id": "c8e7ecb5849edb9a", + "id": "a5557543ccff5889", "type": "tab", - "label": "UPDATE", + "label": "Update", "disabled": false, "info": "", "env": [] }, { - "id": "b3150b13e34b1fe8", + "id": "90223f7ddc082321", + "type": "ui_group", + "name": "preview", + "tab": "e23b837a9f040895", + "order": 2, + "disp": false, + "width": "7", + "collapse": false, + "className": "" + }, + { + "id": "e23b837a9f040895", "type": "ui_tab", - "name": "OpenScan", + "name": "Scan", "icon": "dashboard", - "order": 1, + "order": 2, "disabled": false, "hidden": false }, { - "id": "b6e9c2df6b28ff66", + "id": "5c06cb6bcc371ee6", "type": "ui_base", "theme": { "name": "theme-dark", @@ -61,8 +72,8 @@ "reset": false }, "darkTheme": { - "default": "#097479", - "baseColor": "#097479", + "default": "{{ darktheme-default }}", + "baseColor": "{{ darktheme-basecolor }}", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": true, "reset": false @@ -71,16 +82,17 @@ "name": "Untitled Theme 1", "default": "#4B7930", "baseColor": "#4B7930", - "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" + "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", + "reset": false }, "themeState": { "base-color": { - "default": "#097479", - "value": "#097479", + "default": "{{ base-color-default }}", + "value": "{{ base-color-value }}", "edited": false }, "page-titlebar-backgroundColor": { - "value": "#097479", + "value": "{{ page-titlebar-bgcolor }}", "edited": false }, "page-backgroundColor": { @@ -108,7 +120,7 @@ "edited": false }, "widget-backgroundColor": { - "value": "#097479", + "value": "{{ widget-bgcolor }}", "edited": false }, "widget-borderColor": { @@ -128,190 +140,123 @@ } }, "site": { - "name": "OpenScan 3D Scanner", + "name": "OpenScan", "hideToolbar": "false", "allowSwipe": "false", "lockMenu": "false", "allowTempTheme": "true", "dateFormat": "DD/MM/YYYY", "sizes": { - "sx": 46, - "sy": 46, - "gx": 10, - "gy": 10, + "sx": 48, + "sy": 48, + "gx": 6, + "gy": 6, "cx": 6, "cy": 6, - "px": 6, - "py": 6 + "px": 0, + "py": 0 } } }, { - "id": "729f9ea6e3513c9b", - "type": "ui_group", - "name": "Home", - "tab": "b3150b13e34b1fe8", - "order": 2, - "disp": false, - "width": "6", - "collapse": false, - "className": "" + "id": "34bc0fd2b0f2416c", + "type": "ui_link", + "name": "GitHub", + "link": "https://openscan-org.github.io/OpenScan-Doc/", + "icon": "fa-bookmark", + "target": "iframe", + "order": 6 }, { - "id": "65ae49b64fa0d83e", - "type": "ui_tab", - "name": "Settings", - "icon": "dashboard", - "order": 4, - "disabled": false, - "hidden": false + "id": "23f75a8768250ce8", + "type": "ui_link", + "name": "Patreon", + "link": "https://www.patreon.com/OpenScan", + "icon": "fa-bookmark", + "target": "newtab", + "order": 5 }, { - "id": "4fe6b4c0ade0938a", + "id": "b5fdd57b.15eda8", "type": "ui_group", - "name": "General", - "tab": "65ae49b64fa0d83e", + "name": "Main", + "tab": "15a222ed.d70a7d", "order": 1, - "disp": true, - "width": "6", - "collapse": true, - "className": "" + "disp": false, + "width": 13, + "collapse": false }, { - "id": "0fe66c9190b8a87c", + "id": "db43d646.2074c8", "type": "ui_group", - "name": "Network", - "tab": "65ae49b64fa0d83e", + "name": "OpenScanCloud", + "tab": "15a222ed.d70a7d", "order": 2, "disp": true, "width": "6", - "collapse": true, - "className": "" - }, - { - "id": "93aadb71dee6d977", - "type": "ui_group", - "name": "Camera", - "tab": "65ae49b64fa0d83e", - "order": 4, - "disp": true, - "width": "6", - "collapse": true, - "className": "" - }, - { - "id": "d49a6dfd7fb17096", - "type": "ui_group", - "name": "Motor", - "tab": "65ae49b64fa0d83e", - "order": 5, - "disp": true, - "width": "6", - "collapse": true, - "className": "" - }, - { - "id": "644b3bcc903d46ca", - "type": "ui_group", - "name": "Pinout", - "tab": "65ae49b64fa0d83e", - "order": 6, - "disp": true, - "width": "6", - "collapse": true, - "className": "" + "collapse": false }, { - "id": "e23b837a9f040895", + "id": "15a222ed.d70a7d", "type": "ui_tab", - "name": "Scan", + "name": "Files&Cloud", "icon": "dashboard", - "order": 2, + "order": 3, "disabled": false, "hidden": false }, { - "id": "7aaf184330605300", + "id": "365a30d0dfa83e95", "type": "ui_group", - "name": "Settings", + "name": "settings", "tab": "e23b837a9f040895", "order": 1, "disp": false, - "width": "6", - "collapse": false, - "className": "" - }, - { - "id": "ce9cc9d915dc6eb6", - "type": "ui_group", - "name": "Picamera", - "tab": "e23b837a9f040895", - "order": 2, - "disp": false, - "width": "12", + "width": 7, "collapse": false, "className": "" }, { - "id": "90223f7ddc082321", + "id": "ac7409105cfecac6", "type": "ui_group", - "name": "Arducam", + "name": "advanced", "tab": "e23b837a9f040895", "order": 3, "disp": false, - "width": 12, + "width": 7, "collapse": false, "className": "" }, { - "id": "7625f9c9e8dbc5c6", - "type": "ui_spacer", - "z": "017bd4e4a428bee5", - "name": "spacer", - "group": "", - "order": 4, - "width": 1, - "height": 1 - }, - { - "id": "3b4bd36726be16d5", + "id": "729f9ea6e3513c9b", "type": "ui_group", - "name": "OpenScanCloud", - "tab": "65ae49b64fa0d83e", - "order": 3, - "disp": true, + "name": "Home", + "tab": "b3150b13e34b1fe8", + "order": 2, + "disp": false, "width": "6", "collapse": false, "className": "" }, { - "id": "b5fdd57b.15eda8", + "id": "5b3e5aca21140e9a", "type": "ui_group", - "name": "Main", - "tab": "15a222ed.d70a7d", + "name": "Update", + "tab": "b3150b13e34b1fe8", "order": 1, "disp": false, - "width": 13, - "collapse": false - }, - { - "id": "db43d646.2074c8", - "type": "ui_group", - "name": "OpenScanCloud", - "tab": "15a222ed.d70a7d", - "order": 2, - "disp": true, "width": "6", - "collapse": false + "collapse": false, + "className": "" }, { - "id": "15a222ed.d70a7d", + "id": "b3150b13e34b1fe8", "type": "ui_tab", - "name": "Files&Cloud", + "name": "OpenScan", "icon": "dashboard", - "order": 3, + "order": 1, "disabled": false, - "hidden": false + "hidden": true }, { "id": "ddbd496e.93a288", @@ -339,285 +284,284 @@ "type": "ui_tab", "name": "Update & Info", "icon": "dashboard", - "order": 5, + "order": 4, "disabled": false, "hidden": false }, { - "id": "1f7f7e1e24f5ad9b", + "id": "4390b2ebcbbe104c", "type": "ui_group", - "name": "Initialize", - "tab": "b3150b13e34b1fe8", - "order": 3, - "disp": false, + "name": "General", + "tab": "457102eadc9ddb6c", + "order": 1, + "disp": true, "width": "6", - "collapse": false, + "collapse": true, "className": "" }, { - "id": "5b3e5aca21140e9a", + "id": "8ab79a98e536e0d6", "type": "ui_group", - "name": "Update", - "tab": "b3150b13e34b1fe8", - "order": 1, - "disp": false, + "name": "Network", + "tab": "457102eadc9ddb6c", + "order": 2, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "70d0be671bf03ca7", + "type": "ui_group", + "name": "Pinout", + "tab": "457102eadc9ddb6c", + "order": 6, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "7a3279eea439bcdd", + "type": "ui_group", + "name": "Motor", + "tab": "457102eadc9ddb6c", + "order": 5, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "d324f0b852c2df0a", + "type": "ui_group", + "name": "Camera", + "tab": "457102eadc9ddb6c", + "order": 4, + "disp": true, + "width": "6", + "collapse": true, + "className": "" + }, + { + "id": "12b719cba49817c9", + "type": "ui_group", + "name": "OpenScanCloud", + "tab": "457102eadc9ddb6c", + "order": 3, + "disp": true, "width": "6", "collapse": false, "className": "" }, { - "id": "700f47327133ab68", + "id": "457102eadc9ddb6c", + "type": "ui_tab", + "name": "Settings", + "icon": "dashboard", + "order": 4, + "disabled": false, + "hidden": false + }, + { + "id": "6e339d87c7d5debe", "type": "ui_spacer", - "z": "829d803b6033a693", + "z": "e43a27722b508115", "name": "spacer", - "group": "729f9ea6e3513c9b", - "order": 6, + "group": "db43d646.2074c8", + "order": 1, "width": 1, "height": 1 }, { - "id": "ebf828f29201a53b", + "id": "33b6d7317d1524b8", "type": "ui_spacer", - "z": "829d803b6033a693", + "z": "e43a27722b508115", "name": "spacer", - "group": "729f9ea6e3513c9b", - "order": 8, + "group": "db43d646.2074c8", + "order": 3, "width": 1, "height": 1 }, { - "id": "3b4961c4e72ff58a", + "id": "aaf5b874c52a58aa", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "4fe6b4c0ade0938a", - "order": 6, - "width": 6, + "group": "365a30d0dfa83e95", + "order": 8, + "width": 7, + "height": 1 + }, + { + "id": "2e08d4415665c939", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "365a30d0dfa83e95", + "order": 9, + "width": 1, "height": 1 }, { - "id": "5ef40dca2c6c6aab", + "id": "f8d8740dcbf499fb", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "4fe6b4c0ade0938a", + "group": "365a30d0dfa83e95", "order": 11, - "width": 6, + "width": 1, "height": 1 }, { - "id": "bdd26746cc1e1ba0", + "id": "7ac0cb556740d159", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "3b4bd36726be16d5", - "order": 6, - "width": 2, + "group": "365a30d0dfa83e95", + "order": 13, + "width": 1, "height": 1 }, { - "id": "3584b5ef2b7acb72", + "id": "4de2414e29020c74", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "3b4bd36726be16d5", - "order": 8, - "width": 2, + "group": "90223f7ddc082321", + "order": 2, + "width": 7, "height": 1 }, { - "id": "cac67f0e.f01fa", - "type": "ui_group", - "name": "Button Top", - "tab": "", - "order": 1, - "disp": true, - "width": "6", - "collapse": false + "id": "ac8c60543cb04139", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "ac7409105cfecac6", + "order": 3, + "width": 7, + "height": 1 }, { - "id": "b73c392ffd8ca3f2", + "id": "ce21673092264c38", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "90223f7ddc082321", - "order": 14, - "width": 2, + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, "height": 1 }, { - "id": "89fe04171cd2f35b", + "id": "3f7b77f8a1675d27", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "90223f7ddc082321", - "order": 15, - "width": 2, + "group": "12b719cba49817c9", + "order": 7, + "width": 4, "height": 1 }, { - "id": "80c9c0059de08f02", + "id": "0799b02d12fc3a14", "type": "ui_spacer", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "spacer", - "group": "90223f7ddc082321", - "order": 16, - "width": 2, + "group": "7a3279eea439bcdd", + "order": 25, + "width": 6, "height": 1 }, { - "id": "3fe52603e2ac73b6", - "type": "ui_template", - "z": "829d803b6033a693", - "group": "729f9ea6e3513c9b", - "name": "Background", - "order": 1, - "width": 0, - "height": 0, - "format": "", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": false, - "templateScope": "global", - "className": "", - "x": 110, - "y": 40, - "wires": [ - [] - ] - }, - { - "id": "4468f691.103eb8", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 2, - "width": 3, - "height": 2, - "passthru": false, - "label": "SCAN", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "1", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 100, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", + "order": 7, + "disp": true, + "width": "6", + "collapse": false, + "className": "" }, { - "id": "6560dd25.9e76c4", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 4, - "width": 3, - "height": 2, - "passthru": false, - "label": "Settings", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "3", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 100, - "y": 180, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] + "id": "15edc2ce885dddb3", + "type": "ui_group", + "name": "Colorines", + "tab": "457102eadc9ddb6c", + "order": 8, + "disp": true, + "width": "6", + "collapse": false, + "className": "" }, { - "id": "62cd5288.2805fc", - "type": "ui_ui_control", - "z": "829d803b6033a693", - "name": "", - "events": "all", - "x": 280, - "y": 100, - "wires": [ - [] - ] + "id": "33aff36289823faa", + "type": "ui_group", + "name": "Monitoring", + "tab": "457102eadc9ddb6c", + "order": 9, + "disp": true, + "width": "6", + "collapse": false, + "className": "" }, { - "id": "71e72293.91c6fc", - "type": "ui_button", - "z": "829d803b6033a693", + "id": "bc4e2c03859196c3", + "type": "inject", + "z": "e6f4d02efb300ea9", "name": "", - "group": "729f9ea6e3513c9b", - "order": 3, - "width": 3, - "height": 2, - "passthru": false, - "label": "Files", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "2", - "payloadType": "num", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, "topic": "", - "topicType": "str", - "x": 90, - "y": 140, + "payload": "", + "payloadType": "date", + "x": 100, + "y": 460, "wires": [ [ - "62cd5288.2805fc" + "949bafced17d66d6" ] ] }, { - "id": "e7306ef2.3b4df", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 5, - "width": 3, - "height": 2, - "passthru": false, - "label": "Update&Info", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "4", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 110, - "y": 220, + "id": "949bafced17d66d6", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.flag = global.set('flag_pw',true)\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 460, "wires": [ - [ - "62cd5288.2805fc" - ] + [] ] }, { - "id": "88edad7ca53698fd", + "id": "a1f0ed7d5a9d670e", "type": "inject", - "z": "829d803b6033a693", - "name": "1s", + "z": "e6f4d02efb300ea9", + "name": "", "props": [ { - "p": "payload" + "p": "overwrite", + "v": "false", + "vt": "bool" }, { "p": "topic", @@ -627,112 +571,60 @@ "repeat": "", "crontab": "", "once": true, - "onceDelay": "1", + "onceDelay": "0.1", "topic": "", - "payload": "true", - "payloadType": "bool", - "x": 90, - "y": 400, + "x": 110, + "y": 60, "wires": [ [ - "000a811a215e08d4", - "83c2b5ea51f0fec3", - "88fde4ab78c965d7", - "bee62d2a99cbc63b", - "8e39e4a037487ecd", - "bb84b9e5c7d8e21f", - "7113d7b25a851151", - "c4c1580c289fc7bd" + "544d20f02215011a", + "325314c1a24fe5b4", + "7a4a49f7dbe04e88", + "b1e2491c952f84c9", + "fac6626127bba4f5", + "bc2f0adaf72f97e9", + "ac242724fe7605a6" ] ] }, { - "id": "bd75f33b8a57c522", - "type": "link out", - "z": "829d803b6033a693", - "name": "enable", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "92c98e6ce7cd25f9", - "b33d604c.5f1a6" - ], - "x": 335, - "y": 440, - "wires": [] - }, - { - "id": "000a811a215e08d4", + "id": "544d20f02215011a", "type": "function", - "z": "829d803b6033a693", - "name": "enable", - "func": "msg.enabled = true\nmsg.payload = 1\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "CREATE FACTORY DEFAULT", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 230, - "y": 440, + "x": 330, + "y": 60, "wires": [ [ - "bd75f33b8a57c522" + "c77552216a8bb781" ] ] }, { - "id": "83c2b5ea51f0fec3", - "type": "function", - "z": "829d803b6033a693", - "name": "disable", - "func": "msg.enabled = false\nreturn msg", + "id": "c77552216a8bb781", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "chk files", + "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 240, - "y": 480, + "x": 540, + "y": 60, "wires": [ [ - "6b94bf2295b1b31d" + "960912e90ba5b5bc" ] ] }, - { - "id": "6b94bf2295b1b31d", - "type": "link out", - "z": "829d803b6033a693", - "name": "disable", - "mode": "link", - "links": [ - "a1d29e56599da0bd" - ], - "x": 335, - "y": 480, - "wires": [] - }, - { - "id": "88fde4ab78c965d7", - "type": "function", - "z": "829d803b6033a693", - "name": "write", - "func": "var file = 'status_cloud'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\ncontent = 'ready'\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 230, - "y": 520, - "wires": [ - [] - ] - }, { "id": "960912e90ba5b5bc", "type": "link out", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "started1s", "mode": "link", "links": [ @@ -752,16 +644,43 @@ "e5f38b4a07a5e278", "f0b355967b33dfee", "d0104e0163745993", - "5e7d5e4335d37794" + "5e7d5e4335d37794", + "1dffb799fdf10cbc", + "9fd259de91de1da1", + "fd0258418489839d", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244" ], - "x": 615, - "y": 800, + "x": 645, + "y": 60, "wires": [] }, + { + "id": "325314c1a24fe5b4", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "create path", + "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/','/home/pi/OpenScan/tmp2/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", + "outputs": 1, + "x": 270, + "y": 100, + "wires": [ + [] + ] + }, { "id": "168d72a54504b327", "type": "inject", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "5/0.1s", "props": [ { @@ -780,7 +699,7 @@ "payload": "", "payloadType": "str", "x": 100, - "y": 720, + "y": 380, "wires": [ [ "6c6ef2255a7d39e5" @@ -790,64 +709,106 @@ { "id": "6c6ef2255a7d39e5", "type": "link out", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "repeat 5s/0.1s", "mode": "link", "links": [ "61990987acd0f263", - "2415272f42ce468c" + "2415272f42ce468c", + "6bf8344af427a6ba" ], - "x": 195, - "y": 720, + "x": 205, + "y": 380, "wires": [] }, { - "id": "bee62d2a99cbc63b", - "type": "function", - "z": "829d803b6033a693", - "name": "global", - "func": "global.set('flag_pw', true)\nglobal.set('flag', true)\nglobal.set('combine', false)\nglobal.set('focus', 2838)\nglobal.set('focus1', 0)\nglobal.set('focus2', 0)\n\nglobal.set('focuser', true)\n", + "id": "7a4a49f7dbe04e88", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "LED Status", + "func": "from OpenScan import fade_led, check_hotspot_mode, load_int\n\npin = load_int(\"pin_ringlight1\")\npin2 = load_int(\"pin_ringlight2\")\n\nif check_hotspot_mode():\n msg['mode'] = True\n i=4\n j=30\nelse:\n msg['mode'] = False\n i=2\n j=30\n\nfor x in range (i):\n fade_led(pin,j, 50, True)\n #fade_led(pin2,j, 50, True)\n fade_led(pin,j, 50, False)\n #fade_led(pin2,j, 50, False)\n pass\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 230, - "y": 400, + "x": 270, + "y": 140, "wires": [ [ - "f20da2fc4978b7bf" + "eb1a2387a1eeea76" ] ] }, { - "id": "544d20f02215011a", + "id": "b1e2491c952f84c9", "type": "function", - "z": "829d803b6033a693", - "name": "CREATE FACTORY DEFAULT", - "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cameras':{\n 'imx519':[4656,3496],\n 'imx219':[3280,2464],\n 'imx477':[4056,3040],\n 'ov5647':[2592,1944],\n 'imx378':[3840,2880],\n 'ov9271':[1280,800],\n 'imx290a':[1920,1080],\n 'imx290b':[1920,1080],\n },\n 'cam_AFmode':true,\n 'cam_STmode':true,\n 'cam_stacksize':2,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':0,\n 'cam_saturation':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'hostname':'',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n 'pin_endstop1':24,\n 'pin_endstop2':25,\n 'pin_external':10,\n 'pin_ringlight1':17,\n 'pin_ringlight2':27,\n 'pin_rotor_dir':5,\n 'pin_rotor_enable':23,\n 'pin_rotor_step':6,\n 'pin_tt_dir':9,\n 'pin_tt_enable':22,\n 'pin_tt_step':11,\n 'rotor_acc':1,\n 'rotor_accramp':2000,\n 'rotor_angle':10,\n 'rotor_anglemax':60,\n 'rotor_anglemin':-20,\n 'rotor_anglestart':0,\n 'rotor_delay':0.0001,\n 'rotor_dir':1,\n 'rotor_stepsperrotation':48000,\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n 'tt_acc':1,\n 'tt_accramp':200,\n 'tt_angle':10,\n 'tt_delay':0.0001,\n 'tt_dir':1,\n 'tt_stepsperrotation':3200,\n 'cam_focus':2838,\n 'cam_focus1':0,\n 'cam_focus2':0,\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'downscale_threshold':1000,\n 'turntable_mode':false,\n 'timeout_ringlight':300,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "global", + "func": "global.set('light', 0)\nglobal.set('state1', 0)\nglobal.set('network_ssid',\"\")\nglobal.set('network_password',\"\")\nglobal.set('network_country',\"\")\nglobal.set('flag_pw', true)\nglobal.set('flag',false)\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 310, - "y": 800, + "x": 250, + "y": 320, + "wires": [ + [] + ] + }, + { + "id": "fac6626127bba4f5", + "type": "function", + "z": "e6f4d02efb300ea9", + "name": "enable", + "func": "msg.enabled = true\nmsg.payload = \"\"\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 250, + "y": 280, "wires": [ [ - "c77552216a8bb781" + "200d4b9951b6e066" ] ] }, { - "id": "a1f0ed7d5a9d670e", + "id": "200d4b9951b6e066", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "c8b93b42c720b9cf", + "65518f3d4e3095e5" + ], + "x": 345, + "y": 280, + "wires": [] + }, + { + "id": "bc2f0adaf72f97e9", + "type": "python3-function", + "z": "e6f4d02efb300ea9", + "name": "CAM init", + "func": "from OpenScan import camera\n\ncamera(\"/picam2_init\")\n\nmotor_enable_pin = 22\n\nimport RPi.GPIO as GPIO # import RPi.GPIO module\nGPIO.setmode(GPIO.BCM) # choose BCM or BOARD\nGPIO.setwarnings(False)\nGPIO.setup(22, GPIO.OUT) # set a port/pin as an output\nGPIO.output(22, 0) \n", + "outputs": 1, + "x": 260, + "y": 180, + "wires": [ + [] + ] + }, + { + "id": "8def60b68e21e665", "type": "inject", - "z": "829d803b6033a693", - "name": "", + "z": "e6f4d02efb300ea9", + "name": "FACTORY DEFAULT", "props": [ { "p": "overwrite", - "v": "false", + "v": "true", "vt": "bool" }, { @@ -857,11 +818,11 @@ ], "repeat": "", "crontab": "", - "once": true, + "once": false, "onceDelay": "0.1", "topic": "", - "x": 90, - "y": 800, + "x": 800, + "y": 40, "wires": [ [ "544d20f02215011a" @@ -869,89 +830,181 @@ ] }, { - "id": "c77552216a8bb781", + "id": "eb1a2387a1eeea76", + "type": "link out", + "z": "e6f4d02efb300ea9", + "name": "enable LED", + "mode": "link", + "links": [ + "592ec13d8f8923a9", + "5baf89a2682265f7" + ], + "x": 385, + "y": 140, + "wires": [] + }, + { + "id": "0d8c6bc7887fb3c2", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "365a30d0dfa83e95", + "name": "shutdown+background", + "order": 14, + "width": 7, + "height": 1, + "format": "\n", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "global", + "className": "", + "x": 580, + "y": 140, + "wires": [ + [] + ] + }, + { + "id": "ac242724fe7605a6", "type": "python3-function", - "z": "829d803b6033a693", - "name": "chk files", - "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "rescue incomplete project", + "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", "outputs": 1, - "x": 520, - "y": 800, + "x": 310, + "y": 220, + "wires": [ + [] + ] + }, + { + "id": "4468f691.103eb8", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 1, + "width": 3, + "height": 2, + "passthru": false, + "label": "SCAN", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "1", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 540, "wires": [ [ - "960912e90ba5b5bc", - "ea0e57d83f291e23" + "62cd5288.2805fc" ] ] }, { - "id": "38783aea9cc317a6", - "type": "link in", - "z": "829d803b6033a693", - "name": "factory reset", - "links": [ - "80bccc884b0be297", - "beacc3dc5398fa79" - ], - "x": 135, - "y": 840, + "id": "6560dd25.9e76c4", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 3, + "width": 3, + "height": 2, + "passthru": false, + "label": "Settings", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "3", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 100, + "y": 620, "wires": [ [ - "544d20f02215011a" + "62cd5288.2805fc" ] ] }, { - "id": "f20da2fc4978b7bf", - "type": "link out", - "z": "829d803b6033a693", - "name": "global", - "mode": "link", - "links": [ - "d14bbbb446d45e39" - ], - "x": 345, - "y": 400, - "wires": [] + "id": "62cd5288.2805fc", + "type": "ui_ui_control", + "z": "e6f4d02efb300ea9", + "name": "", + "events": "all", + "x": 280, + "y": 540, + "wires": [ + [] + ] }, { - "id": "8e39e4a037487ecd", - "type": "python3-function", - "z": "829d803b6033a693", - "name": "create log", - "func": "import subprocess\nfrom time import sleep\nsleep(20)\n\n\nlog = '############################################DMESG############################################\\n'\nlog += subprocess.getoutput(\"dmesg\")\nlog += '\\n############################################SYSLOG############################################\\n'\nlog += subprocess.getoutput(\"tail -10000 /var/log/syslog\")\n\nwith open('/home/pi/OpenScan/tmp/log.txt', 'w+') as file:\n file.write(log)\n\nreturn msg", - "outputs": 1, - "x": 240, - "y": 560, + "id": "71e72293.91c6fc", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 2, + "width": 3, + "height": 2, + "passthru": false, + "label": "Files", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "2", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 90, + "y": 580, "wires": [ - [] + [ + "62cd5288.2805fc" + ] ] }, { - "id": "be8cae9cf6f3585f", - "type": "ui_template", - "z": "829d803b6033a693", - "group": "1f7f7e1e24f5ad9b", - "name": "first start", - "order": 1, - "width": 6, - "height": 3, - "format": "

Initial Setup

\n

Note, that you can always adjust these and other settings in the settings menu, which will appear after this setup stage. 

\n

Model

\n

Please select the OpenScan Version - this will only affect the motor settings (acceleration, gear ratio, speed).

\n

Camera

\n

- Pi Camera v1, v2, HQ, Arducam IMX519, IMX290, IMX378, OV9281 are connected through the ribbon cable. If you encounter any issues, please check the cable's orientation

\n

- DSLR (gphoto) - can be used with a wide range of cameras, which can be connected and controlled via USB. Check GPhoto if your camera is supported

\n

- External Camera - Can be used to connect your camera trigger to the GPIO pins on the front of the pi shield. This can be used with any (modified) remote shutter release, and thus it is possible to use Smartphones, DSLR and compact cameras

", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": true, - "templateScope": "local", + "id": "e7306ef2.3b4df", + "type": "ui_button", + "z": "e6f4d02efb300ea9", + "name": "", + "group": "729f9ea6e3513c9b", + "order": 4, + "width": 3, + "height": 2, + "passthru": false, + "label": "Update&Info", + "tooltip": "", + "color": "", + "bgcolor": "", "className": "", - "x": 280, - "y": 40, + "icon": "", + "payload": "4", + "payloadType": "num", + "topic": "", + "topicType": "str", + "x": 110, + "y": 660, "wires": [ - [] + [ + "62cd5288.2805fc" + ] ] }, { "id": "8955d11554f55e63", "type": "ui_button", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "", "group": "5b3e5aca21140e9a", "order": 1, @@ -969,7 +1022,7 @@ "topic": "", "topicType": "str", "x": 120, - "y": 280, + "y": 720, "wires": [ [ "1e7457ea9c2c5e09" @@ -979,145 +1032,44 @@ { "id": "1e7457ea9c2c5e09", "type": "link out", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "update", "mode": "link", "links": [ "39a502b38837273d" ], "x": 245, - "y": 280, - "wires": [] - }, - { - "id": "bb84b9e5c7d8e21f", - "type": "python3-function", - "z": "829d803b6033a693", - "name": "rescue incomplete project", - "func": "#if project has not been done properly, this is a way to rescue the file\n\nfrom os import system\nfrom os.path import isfile\nfrom time import strftime\nfrom OpenScan import load_str\n\nbasepath = '/home/pi/OpenScan/'\nzippath = basepath + 'tmp/tmp.zip'\nprojectname=load_str(\"routine_projectname\")\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')", - "outputs": 1, - "x": 290, - "y": 600, - "wires": [ - [] - ] - }, - { - "id": "a291fc98e4269c1b", - "type": "ui_text", - "z": "829d803b6033a693", - "group": "729f9ea6e3513c9b", - "order": 7, - "width": 4, - "height": 1, - "name": "version", - "label": "Version:", - "format": "{{msg.firmware}}", - "layout": "row-center", - "className": "", - "x": 460, - "y": 360, + "y": 720, "wires": [] }, { - "id": "7113d7b25a851151", + "id": "245e4341d4fb611c", "type": "function", - "z": "829d803b6033a693", - "name": "FIRMWARE VERSION", - "func": "msg.firmware = '2022-08-16'\nreturn msg", + "z": "e6f4d02efb300ea9", + "name": "pinmap_v2", + "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 280, - "y": 360, + "x": 790, + "y": 540, "wires": [ [ - "a291fc98e4269c1b", - "ec5cefa70ff535f7" - ] - ] - }, - { - "id": "ec5cefa70ff535f7", - "type": "ui_text", - "z": "829d803b6033a693", - "group": "ddbd496e.93a288", - "order": 2, - "width": 6, - "height": 1, - "name": "current version", - "label": "Current version:", - "format": "{{msg.firmware}}", - "layout": "row-spread", - "className": "", - "x": 480, - "y": 320, - "wires": [] - }, - { - "id": "c4c1580c289fc7bd", - "type": "python3-function", - "z": "829d803b6033a693", - "name": "create path", - "func": "import os\n\npaths = ['/home/pi/OpenScan/scans/preview/']\n\n\nfor i in paths:\n if not os.path.isdir(i):\n os.mkdir(i)", - "outputs": 1, - "x": 250, - "y": 640, - "wires": [ - [] - ] - }, - { - "id": "06d33bb8951ce668", - "type": "ui_template", - "z": "829d803b6033a693", - "group": "", - "name": "donate", - "order": 2, - "width": "0", - "height": "0", - "format": "\n\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "global", - "className": "", - "x": 450, - "y": 40, - "wires": [ - [] - ] - }, - { - "id": "245e4341d4fb611c", - "type": "function", - "z": "829d803b6033a693", - "name": "pinmap_v2", - "func": "msg = { \n'overwrite':true,\n'settings':{\n 'pin_rotor_endstop':27,\n 'pin_tt_endstop':5,\n 'pin_extra_endstop':26,\n 'pin_external':25,\n 'pin_ringlight1':24,\n 'pin_ringlight2':24,\n 'pin_rotor_dir':23,\n 'pin_rotor_enable':19,\n 'pin_rotor_step':22,\n 'pin_tt_dir':6,\n 'pin_tt_enable':19,\n 'pin_tt_step':16,\n 'pin_extra_dir':21,\n 'pin_extra_step':20,\n 'pin_extra_enable':19,\n 'extra_acc':1,\n 'extra_accramp':200,\n 'extra_angle':10,\n 'extra_delay':0.0001,\n 'extra_dir':1,\n 'extra_stepsperrotation':3200,\n}}\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 870, - "y": 40, - "wires": [ - [ - "627406f3611511dc" + "627406f3611511dc" ] ] }, { "id": "627406f3611511dc", "type": "python3-function", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "write", "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", "outputs": 1, - "x": 1010, - "y": 40, + "x": 930, + "y": 540, "wires": [ [ "50eeb3e362f9027f" @@ -1127,7 +1079,7 @@ { "id": "88b1bddde110298a", "type": "inject", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "", "props": [ { @@ -1145,8 +1097,8 @@ "once": false, "onceDelay": "0.1", "topic": "", - "x": 730, - "y": 40, + "x": 650, + "y": 540, "wires": [ [ "245e4341d4fb611c" @@ -1156,7 +1108,7 @@ { "id": "50eeb3e362f9027f", "type": "link out", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "started1s", "mode": "link", "links": [ @@ -1176,37 +1128,32 @@ "e5f38b4a07a5e278", "f0b355967b33dfee", "d0104e0163745993", - "5e7d5e4335d37794" + "5e7d5e4335d37794", + "b4c843620c251c43", + "3876d5cbd248592b", + "a4c81754c148b86f", + "2e9b29c70969cf01", + "2477f81cddc8fa31", + "29036b35dfd672c6", + "592ec13d8f8923a9", + "cb40b9341bd22a28", + "d1efcd5fa9d25785", + "da61581182b7299e", + "2afb6a45c73fa244" ], - "x": 1095, - "y": 40, - "wires": [] - }, - { - "id": "ea0e57d83f291e23", - "type": "debug", - "z": "829d803b6033a693", - "name": "", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "false", - "statusVal": "", - "statusType": "auto", - "x": 610, - "y": 860, + "x": 1015, + "y": 540, "wires": [] }, { "id": "4f3121f158f06a61", "type": "python3-function", - "z": "829d803b6033a693", - "name": "Rotor left", - "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',100,True)\n\nmotorrun('tt',360,True)\nmotorrun('extra',360,True)", + "z": "e6f4d02efb300ea9", + "name": "motor run", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", "outputs": 1, - "x": 940, - "y": 80, + "x": 860, + "y": 580, "wires": [ [] ] @@ -1214,7 +1161,7 @@ { "id": "4a8a04b1e5dca8fe", "type": "inject", - "z": "829d803b6033a693", + "z": "e6f4d02efb300ea9", "name": "run rotor till endstop", "props": [ { @@ -1232,8 +1179,8 @@ "topic": "", "payload": "", "payloadType": "date", - "x": 770, - "y": 80, + "x": 690, + "y": 580, "wires": [ [ "4f3121f158f06a61" @@ -1241,747 +1188,756 @@ ] }, { - "id": "828e5298.d2192", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 9, - "width": 2, - "height": 1, - "passthru": false, - "label": "⇐", - "tooltip": "", - "color": "", - "bgcolor": "", + "id": "c8167775e3401fad", + "type": "ui_template", + "z": "e6f4d02efb300ea9", + "group": "729f9ea6e3513c9b", + "name": "infotext", + "order": 4, + "width": 0, + "height": 0, + "format": "

What's new?

\n
    \n
  • speed improvement 2-3x
  • \n
  • currently tested on OpenScan Mini + IMX519 with RPi 4
  • \n
  • optimized toolpath
  • \n
  • more responsive user interface
  • \n
  • hotspot mode (when no wireless network available ssid: openscan pw: opensource
  • \n
  • preview features and sharpness
  • \n
  • partial background masking
  • \n
  • no more autofocus --> instead you can set a min and max focus distance
  • \n
\nnote, that this is still an early beta and there might be some unintended bugs. please reach out to info@openscan.eu if you run into any issues.", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 400, + "x": 580, + "y": 260, "wires": [ - [ - "b12e54fb.3141b8" - ] + [] ] }, { - "id": "96c7e241.458e6", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 10, - "width": 2, - "height": 1, - "passthru": false, - "label": "⇒", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 440, + "id": "6a3d9acbe097a3d2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 120, "wires": [ [ - "37f52dd4.bd7572" + "cb6ebdabaaf7d0da" ] ] }, { - "id": "2e854876.6b6008", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 6, - "width": 2, - "height": 1, - "passthru": true, - "label": "⇑", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 280, + "id": "7ef6f1b5c67201fe", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 120, "wires": [ - [ - "555aea34.b3b5e4" - ] + [] ] }, { - "id": "753817f.1b9b3e8", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 7, - "width": 2, - "height": 1, - "passthru": true, - "label": "⇓", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 320, + "id": "86f7d1b2d763f6e2", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 160, "wires": [ [ - "9905e0c9.dddcd" + "c8a3fde5206ce1ae" ] ] }, { - "id": "8775044.3aa3ef8", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 8, - "width": 2, - "height": 1, - "name": "", - "label": "Turntable", - "format": "", - "layout": "row-left", - "className": "", - "x": 100, - "y": 360, - "wires": [] - }, - { - "id": "9e8a2d23.bf6ce", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 5, - "width": 2, - "height": 1, - "name": "", - "label": "Rotor", - "format": "", - "layout": "row-left", - "className": "", - "x": 90, + "id": "fd799c931139764d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, "y": 240, - "wires": [] + "wires": [ + [ + "87be854db758a9a6" + ] + ] }, { - "id": "555aea34.b3b5e4", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, + "id": "d5140d455122c49a", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, - "x": 220, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, "y": 280, "wires": [ [ - "46e00b45.c24ca4" + "9daea4bd57f7a00e" ] ] }, { - "id": "9905e0c9.dddcd", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 320, - "wires": [ - [ - "6ee089cb343a35ef" - ] - ] - }, - { - "id": "b12e54fb.3141b8", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 400, - "wires": [ - [ - "c1871a2b9af5419a" - ] - ] - }, - { - "id": "37f52dd4.bd7572", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 440, - "wires": [ - [ - "42b9f1fc49e69f54" - ] - ] - }, - { - "id": "46e00b45.c24ca4", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Rotor left", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('rotor',load_int('rotor_angle'))", - "outputs": 1, - "x": 360, - "y": 280, - "wires": [ - [] - ] - }, - { - "id": "6ee089cb343a35ef", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Rotor right", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('rotor',-load_int('rotor_angle'))", - "outputs": 1, - "x": 370, - "y": 320, - "wires": [ - [] - ] - }, - { - "id": "42b9f1fc49e69f54", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "TT right", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('tt',-load_int('tt_angle'))", + "id": "194f3590dd4f6e3d", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, - "x": 360, - "y": 440, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 240, "wires": [ [] ] }, { - "id": "c1871a2b9af5419a", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "TT left", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('tt',load_int('tt_angle'))", + "id": "2de69452e829d780", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, - "x": 350, - "y": 400, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 280, "wires": [ [] ] }, { - "id": "aebad788761dce4a", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "routine_photocount", + "id": "58e565fea35cb667", + "type": "ui_text_input", + "z": "481edaf6db5a7a54", + "name": "", "label": "", "tooltip": "", - "group": "7aaf184330605300", - "order": 14, - "width": 3, + "group": "365a30d0dfa83e95", + "order": 3, + "width": 4, "height": 1, - "passthru": false, - "outs": "end", + "passthru": true, + "mode": "text", + "delay": "0", "topic": "", - "topicType": "str", - "min": "10", - "max": "300", - "step": "10", + "sendOnBlur": true, "className": "", - "x": 350, - "y": 540, + "topicType": "str", + "x": 320, + "y": 80, "wires": [ [ - "ce28a0b5bfb0d5a1" + "734ac3bff2df6837" ] ] }, { - "id": "107a030938cbfea9", + "id": "97170908e1f4ac55", "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.payload=\"default\"\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 190, - "y": 540, + "y": 80, "wires": [ [ - "aebad788761dce4a" + "58e565fea35cb667" ] ] }, { - "id": "ce28a0b5bfb0d5a1", + "id": "734ac3bff2df6837", "type": "function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "write", - "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\n\nvar file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 510, - "y": 540, + "y": 80, "wires": [ [] ] }, { - "id": "84d6b96c8ebaac96", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadF", - "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 580, - "wires": [ - [ - "470b10726d298834" - ] - ] - }, - { - "id": "470b10726d298834", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "shutter ", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 16, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "1", - "max": "700", - "step": "1", - "className": "", - "x": 310, - "y": 580, + "id": "1dffb799fdf10cbc", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 55, + "y": 80, "wires": [ [ - "44c3947a9b92d32d" + "97170908e1f4ac55", + "6a3d9acbe097a3d2", + "86f7d1b2d763f6e2", + "fd799c931139764d", + "d5140d455122c49a" ] ] }, { - "id": "44c3947a9b92d32d", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "id": "a0156eaac7dd35e5", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "shutter", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nimport math\n\n\ncamera('/picam2_exposure?exposure=' + str(int(msg['payload']*1000)))\n\nreturn msg\n", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], "x": 510, - "y": 580, + "y": 200, "wires": [ [] ] }, { - "id": "069bcf58b1fe44cd", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 13, - "width": 3, - "height": 1, - "name": "photocount", - "label": "Photos", - "format": "", - "layout": "row-left", - "className": "", - "x": 670, - "y": 540, - "wires": [] - }, - { - "id": "8dc7df1de59cb03a", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 15, - "width": 3, - "height": 1, - "name": "shutter", - "label": "Shutter (ms)", - "format": "", - "layout": "row-left", - "className": "", - "x": 650, - "y": 580, - "wires": [] - }, - { - "id": "cc69dba8d54a29dd", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "Crop X", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 18, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", + "id": "c7f5808d753480d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": true, + "onceDelay": "6", "topic": "", - "topicType": "str", - "min": "0", - "max": "99", - "step": "1", - "className": "", - "x": 320, - "y": 620, + "payload": "", + "payloadType": "date", + "x": 170, + "y": 200, "wires": [ [ - "c2b2ab5524271123" + "11f41a6030578ef4" ] ] }, { - "id": "e3a90602605fb9e9", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "Crop Y", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 20, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0", - "max": "99", - "step": "1", - "className": "", + "id": "11f41a6030578ef4", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], "x": 310, - "y": 660, + "y": 200, "wires": [ [ - "26f17a7f406df73c" + "a0156eaac7dd35e5" ] ] }, { - "id": "9c6b48b7b4cc4e1a", + "id": "855cbcadef1163c5", "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "enable", + "func": "msg.light = global.get('light')\nmsg.state1 = global.get('state1')\nmsg.flag = global.get('flag')\n\n\nvar min = 1;\nvar max = 100000;\nvar random = Math.floor(Math.random() * (max - min + 1)) + min;\n\nvar formatted = random.toString().padStart(3, '0');\nmsg.payload=\"/tmp2/preview.jpg?ts=\" + Date.now().toString();\n\nif (global.get('flag_pw') == false){\n if (msg.flag == true){\n return msg\n }\n return \n}\nelse{\n return msg\n}\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 190, - "y": 620, + "x": 250, + "y": 840, "wires": [ [ - "cc69dba8d54a29dd" + "d1b87196ae5373ed", + "41e6a4649b6afbfb", + "2fd24f8e8e9c08b7", + "85a268108250ba88" ] ] }, { - "id": "c470fd0b15356206", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 660, + "id": "1a443e20a973d2f1", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw true", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "true", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 630, + "y": 760, "wires": [ - [ - "e3a90602605fb9e9" - ] + [] ] }, { - "id": "c2b2ab5524271123", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 620, + "id": "d1b87196ae5373ed", + "type": "change", + "z": "481edaf6db5a7a54", + "name": "flag_pw false", + "rules": [ + { + "t": "set", + "p": "flag_pw", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 430, + "y": 760, "wires": [ [] ] }, { - "id": "26f17a7f406df73c", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "id": "03d92601c62b79d4", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "4s/0.5", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "0.1", + "crontab": "", + "once": true, + "onceDelay": "4", + "topic": "Repeat", + "payload": "0.1", + "payloadType": "str", + "x": 100, + "y": 840, + "wires": [ + [ + "855cbcadef1163c5" + ] + ] + }, + { + "id": "41e6a4649b6afbfb", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Take Preview Shot", + "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\n#return msg\n\nmsg['payload']=\"/tmp2/preview.jpg?ts=\"+str(int(time()))\n\nif msg['flag'] == True:\n return msg\n\n\n#if status!=\"--READY--\":\n# return msg\n\n#msg['preview'] = True\n\ncamera('/picam2_take_photo')\n\nreturn msg\n", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 660, + "x": 450, + "y": 800, "wires": [ - [] + [ + "1a443e20a973d2f1", + "296636b7467fc745" + ] ] }, { - "id": "fecf5cff888bb570", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 17, - "width": 3, - "height": 1, - "name": "cropx", - "label": "{{msg.crop1}}", - "format": "", - "layout": "row-left", + "id": "85a268108250ba88", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "preview_arducam", + "order": 1, + "width": 7, + "height": 9, + "format": "\n\n
\n \n
\n \n
\n
\n \n \n \n
\n\n \n\n\n\n \n \n
\n \n \n \n \n \n \n
\n \n
\n \n\n\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", "className": "", - "x": 690, - "y": 620, - "wires": [] + "x": 450, + "y": 840, + "wires": [ + [ + "417f653ca0dfdcfc", + "180476141c2a44ad" + ] + ] }, { - "id": "0ee4950bd21498bd", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 19, - "width": 3, - "height": 1, - "name": "cropy", - "label": "{{msg.crop2}}", - "format": "", - "layout": "row-left", - "className": "", - "x": 690, - "y": 660, + "id": "296636b7467fc745", + "type": "link out", + "z": "481edaf6db5a7a54", + "name": "link out 1", + "mode": "link", + "links": [ + "2c58a1a66c4a8c11" + ], + "x": 575, + "y": 800, "wires": [] }, { - "id": "ebbf11b55d758806", - "type": "ui_text_input", - "z": "1613373abaf77a2c", - "name": "", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 4, - "width": 3, - "height": 1, - "passthru": true, - "mode": "text", - "delay": "0", - "topic": "", - "sendOnBlur": true, - "className": "", - "topicType": "str", - "x": 320, - "y": 500, + "id": "417f653ca0dfdcfc", + "type": "delay", + "z": "481edaf6db5a7a54", + "name": "lmt 0.2/s", + "pauseType": "rate", + "timeout": "0.1", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "0.2", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": true, + "allowrate": false, + "outputs": 1, + "x": 640, + "y": 840, "wires": [ [ - "67385b196c517ac6" + "e864254b18c23dd1" ] ] }, { - "id": "f4b3112a9ec6c487", + "id": "e864254b18c23dd1", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "motorrun", + "func": "from OpenScan import motorrun, load_int, load_bool\n\nif 'payload' not in msg:\n return\nenable_endstop = load_bool('rotor_enable_endstop')\n\nif msg['payload'] == \"up\":\n motorrun('rotor',load_int('rotor_angle'), enable_endstop)\nif msg['payload'] == \"down\":\n motorrun('rotor',-load_int('rotor_angle'), enable_endstop)\nif msg['payload'] == \"left\":\n motorrun('tt',load_int('tt_angle'), enable_endstop)\nif msg['payload'] == \"right\":\n motorrun('tt',-load_int('tt_angle'), enable_endstop)", + "outputs": 1, + "x": 780, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "180476141c2a44ad", "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.payload=\"default\"\nreturn msg;", + "z": "481edaf6db5a7a54", + "name": "global", + "func": "if (typeof msg.light !== \"undefined\"){\n global.set('light',msg.light)\n}\nif (typeof msg.state1 !== \"undefined\"){\n global.set('state1',msg.state1)\n}\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 190, - "y": 500, + "x": 630, + "y": 880, "wires": [ [ - "ebbf11b55d758806" + "8cbdbfecbd12ef83" ] ] }, { - "id": "67385b196c517ac6", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "id": "1fe18f3b0b52aabd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "LED", + "func": "from OpenScan import ringlight\nfrom time import time\n\nstarttime = time()\n\nif 'light' in msg:\n val = msg['light']\n while time()-starttime<0.02:\n if val == 0:\n ringlight(1,False)\n ringlight(2,False)\n\n elif val == 1:\n ringlight(1,True)\n ringlight(2,True)\n\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 500, + "x": 870, + "y": 880, "wires": [ [] ] }, { - "id": "4dd7285c2b0fd79b", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "ringlight", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 12, - "width": 3, - "height": 1, - "passthru": true, - "outs": "all", - "topic": "", - "topicType": "str", - "min": 0, - "max": "3", - "step": 1, - "className": "", - "x": 320, - "y": 700, + "id": "2fd24f8e8e9c08b7", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "load advanced", + "func": "from OpenScan import load_bool\n\nif 'state1' in msg:\n if msg['state1'] == 0:\n msg['payload']={\"group\":{\"hide\":[\"Scan_advanced\"],\"show\":[]}}\n else:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Scan_advanced\"]}}\n return msg", + "outputs": 1, + "x": 440, + "y": 720, "wires": [ [ - "873dace18a23fdf2" + "923be3b2b25224b4" ] ] }, { - "id": "873dace18a23fdf2", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "LED", - "func": "from OpenScan import ringlight\nval = msg['payload']\n\nif val == 0:\n ringlight(1,False)\n ringlight(2,False)\nelif val == 1:\n ringlight(1,False)\n ringlight(2,True)\nelif val == 2:\n ringlight(1,True)\n ringlight(2,False)\nelif val == 3:\n ringlight(1,True)\n ringlight(2,True)", - "outputs": 1, - "x": 510, - "y": 700, + "id": "923be3b2b25224b4", + "type": "ui_ui_control", + "z": "481edaf6db5a7a54", + "name": "change visibility", + "events": "all", + "x": 640, + "y": 720, "wires": [ [] ] }, { - "id": "9e30e33a1520fee0", + "id": "c8a3fde5206ce1ae", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "shutter", + "order": 4, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 160, + "wires": [ + [ + "034ec9f59e50a361", + "a0156eaac7dd35e5" + ] + ] + }, + { + "id": "034ec9f59e50a361", "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "msg.payload = 0\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 190, - "y": 700, + "x": 510, + "y": 160, + "wires": [ + [] + ] + }, + { + "id": "87be854db758a9a6", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropy", + "order": 7, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 240, "wires": [ [ - "4dd7285c2b0fd79b" + "194f3590dd4f6e3d" ] ] }, { - "id": "7dd287f40385922f", + "id": "9daea4bd57f7a00e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Cropx", + "order": 6, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 310, + "y": 280, + "wires": [ + [ + "2de69452e829d780" + ] + ] + }, + { + "id": "cb6ebdabaaf7d0da", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "name": "Photos", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 120, + "wires": [ + [ + "7ef6f1b5c67201fe" + ] + ] + }, + { + "id": "82ecd3cd971cb7ea", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 2, + "width": 3, + "height": 1, + "name": "projectname", + "label": "Projectname", + "format": "", + "layout": "row-left", + "className": "", + "x": 530, + "y": 40, + "wires": [] + }, + { + "id": "ed2974731fb8a84e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "threshold", + "order": 5, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", + "className": "", + "x": 320, + "y": 520, + "wires": [ + [ + "06e1e19835a9816e" + ] + ] + }, + { + "id": "8cbdbfecbd12ef83", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "led", + "func": "from OpenScan import fade_led, ringlight, load_int\n\npin = load_int('pin_ringlight1')\n\n\nif 'light' in msg:\n val = msg['light']\n\n if val ==1:\n fade_led(pin,50, 100, True)\n\n else:\n fade_led(pin,50, 100, False)\n\nreturn msg", + "outputs": 1, + "x": 750, + "y": 880, + "wires": [ + [ + "1fe18f3b0b52aabd" + ] + ] + }, + { + "id": "06e1e19835a9816e", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "2d5b1eb4380ae5a8", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_mask_threshold'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 520, + "wires": [ + [ + "ed2974731fb8a84e" + ] + ] + }, + { + "id": "7dd287f40385922f", "type": "ui_button", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "start ", - "group": "7aaf184330605300", - "order": 21, + "group": "365a30d0dfa83e95", + "order": 10, "width": 2, "height": 1, "passthru": false, @@ -1995,23 +1951,23 @@ "payloadType": "date", "topic": "enabled", "topicType": "str", - "x": 150, - "y": 880, + "x": 130, + "y": 1040, "wires": [ [ - "431f917c2541ae48", "33d94a04b96a2de0", - "6d15f717d5a11002" + "6d15f717d5a11002", + "9a6b30a0175a8ecd" ] ] }, { "id": "579f2211199fd6ab", "type": "ui_button", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "stop", - "group": "7aaf184330605300", - "order": 23, + "group": "365a30d0dfa83e95", + "order": 12, "width": 2, "height": 1, "passthru": false, @@ -2025,8 +1981,8 @@ "payloadType": "global", "topic": "", "topicType": "str", - "x": 810, - "y": 960, + "x": 490, + "y": 1100, "wires": [ [ "1787f08ed7070ddd", @@ -2034,33 +1990,15 @@ ] ] }, - { - "id": "431f917c2541ae48", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Routine", - "func": "from OpenScan import load_bool, load_str, load_int, load_float, motorrun, create_coordinates, take_photo, save, load_bool, camera\nfrom time import sleep, strftime, time\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system\nfrom os.path import isfile\nfrom Arducam import Focuser\n\nif load_str(\"status_internal_cam\")==\"no camera found\" or load_str(\"status_internal_cam\")[:5]==\"Featu\":\n return\n\nsave('status_internal_cam','Routine-preparing')\n\nprojectname=load_str(\"routine_projectname\")\nphotocount = load_int('routine_photocount') #vorher point_count\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nangle_start = load_int('rotor_anglestart')\ncam = load_str('camera')\nSTmode = load_bool('cam_STmode')\ntt_mode = load_bool('turntable_mode')\ncam_delay_after = load_float('cam_delay_after')\ncam_delay_before = load_float('cam_delay_before')\n\nif cam == 'imx519' and STmode == True:\n focuser = Focuser('/dev/v4l-subdev1')\n stacksize = load_int('cam_stacksize')\n focus1 = load_int('cam_focus1')\n focus2 = load_int('cam_focus2')\n if focus1 > focus2:\n focus2 = focus1\n focus1 = load_int('cam_focus2') \n focusstep = int((focus2-focus1)/(stacksize - 1))\n\ncounter = 0\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp/tmp.jpg'\nzippath = basepath + 'tmp/tmp.zip'\n\nif not 'projectcode' in msg:\n projectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n msg['projectcode'] = projectcode\n msg['counter'] = -1\n if isfile(zippath):\n system('rm ' + zippath)\n sleep(1)\n\nprojectcode = msg['projectcode']\nmsg['counter'] += 1\n\nif tt_mode == False:\n coordinates = create_coordinates(angle_min,angle_max,photocount)\nelse:\n angle_start = 0\n coordinates = []\n for i in range (photocount):\n coordinates.append([0,360/photocount*(i+1)])\n\nposition_last = (angle_start , 0)\n\nzip = ZipFile(zippath, \"a\",ZIP_DEFLATED, allowZip64=True)\n\nstarttime = time()\n\nfor position in coordinates:\n counter += 1\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n\n while load_str('status_internal_cam') == 'Routine-paused':\n sleep(0.2)\n\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n\n rotor_angle = position_last[0] - position[0]\n if abs(rotor_angle) > 180:\n rotor_angle = -360 * rotor_angle/abs(rotor_angle) + rotor_angle\n\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n # tt_angle = -360 * tt_angle/abs(tt_angle) + tt_angle\n \n motorrun('rotor', rotor_angle)\n motorrun('tt', tt_angle)\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n while load_str('status_internal_cam') == 'Routine-paused':\n sleep(0.2)\n\n msg['cropx'] = load_int('cam_cropx')\n msg['cropy'] = load_int('cam_cropy')\n msg['rotation'] = load_int('cam_rotation')\n msg['filepath_in'] = 'tmp/tmp.jpg'\n msg['filepath_out'] = 'tmp/tmp.jpg'\n msg['filepath'] = 'tmp/tmp.jpg'\n\n if counter < 6:\n ETA = ''\n sleep(cam_delay_before)\n if STmode == True:\n counter2 = 0\n for focus in range (stacksize):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n while load_str('status_internal_cam') == 'Routine-paused':\n sleep(0.2)\n counter2 += 1\n save('status_internal_cam','Routine-' + str(counter) + '/' + str(photocount) + ' F' + str(counter2) + ETA)\n focuser.write(focus1 + focus * focusstep)\n take_photo('tmp/tmp.jpg')\n camera('/crop',msg)\n zip.write(temppath, projectname + '_' + str(msg['counter']) + '_' + str(counter) + '-' + str(focus) + \".jpg\")\n system('cp ' + temppath + ' ' + basepath +'tmp/preview.jpg')\n elif cam != 'external':\n save('status_internal_cam','Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n\n if cam == 'gphoto':\n camera('/gphoto_capture', msg)\n if cam in ('usb_webcam','imx219','ov5647','imx477','imx290a','imx290b','imx378','ov9281','imx519'):\n take_photo('tmp/tmp.jpg')\n camera('/crop',msg)\n \n zip.write(temppath, projectname + '_' + str(msg['counter']) + '_' + str(counter) + \".jpg\")\n system('cp ' + temppath + ' ' + basepath +'tmp/preview.jpg')\n elif cam == 'external':\n camera('external_capture')\n save('status_internal_cam','Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n\n ETA = '-ETA:'+str(int((photocount/counter - 1)*(time() - starttime)))+'/'+str(int(photocount/counter*(time() - starttime)))+'s'\n sleep(cam_delay_after)\n\n position_last = position\n\nzip.close()\n\nsave('status_internal_cam','Routine-done')\n\nmotorrun('rotor',position_last[0] - angle_start)\nmotorrun('tt',position_last[1])\n\nsave('status_internal_cam','--READY--')\n\nif load_bool('routine_secondpass')==True:\n msg['topic'] = 'Scan done'\n msg['payload'] = 'Do you want to run another pass or finish this project?'\n msg['enabled'] = False\n return msg,None\n\nreturn None,msg\n", - "outputs": 2, - "x": 300, - "y": 880, - "wires": [ - [ - "db7eea74d3bf892b" - ], - [ - "0b8661103366f834" - ] - ] - }, { "id": "1787f08ed7070ddd", "type": "python3-function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "stop", "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", "outputs": 1, - "x": 930, - "y": 960, + "x": 630, + "y": 1100, "wires": [ [] ] @@ -2068,21 +2006,22 @@ { "id": "e9b13dfd9f8d3711", "type": "link out", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "", "mode": "link", "links": [ "8367cfa0bf5bc5df", - "b33d604c.5f1a6" + "b33d604c.5f1a6", + "c8b93b42c720b9cf" ], "x": 395, - "y": 840, + "y": 1000, "wires": [] }, { "id": "9654deebb668e012", "type": "inject", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "1s", "props": [ { @@ -2101,7 +2040,7 @@ "payload": "", "payloadType": "date", "x": 290, - "y": 1000, + "y": 1140, "wires": [ [ "c1c044f3c2139f68" @@ -2111,20 +2050,17 @@ { "id": "8367cfa0bf5bc5df", "type": "link in", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "start routine", "links": [ - "210ef5246d1a8790", - "84608db962fd9932", + "200d4b9951b6e066", "8689e938.dd9e38", - "f20f2dbc.0f123", "e9b13dfd9f8d3711", - "96bdb9417e38810f", - "fb13752beddee9f2", - "bd75f33b8a57c522" + "f20f2dbc.0f123", + "fb13752beddee9f2" ], - "x": 55, - "y": 880, + "x": 45, + "y": 1040, "wires": [ [ "7dd287f40385922f" @@ -2134,602 +2070,702 @@ { "id": "fb13752beddee9f2", "type": "link out", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "", "mode": "link", "links": [ "2f4c0f98.dee2", "8367cfa0bf5bc5df", - "b33d604c.5f1a6" + "b33d604c.5f1a6", + "c8b93b42c720b9cf" ], - "x": 895, - "y": 920, + "x": 525, + "y": 1040, "wires": [] }, { - "id": "95439678bb2df2a2", + "id": "33d94a04b96a2de0", "type": "function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "enable", - "func": "msg.flag = global.get('flag')\nif (global.get('flag_pw')== true){\n return msg\n}\n", + "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 230, - "y": 1220, + "x": 290, + "y": 1100, "wires": [ [ - "04cc2467807d2d6b", - "14f9617b5b301318" + "579f2211199fd6ab" ] ] }, { - "id": "948a3ae4444685f2", - "type": "change", - "z": "1613373abaf77a2c", - "name": "flag_pw true", - "rules": [ - { - "t": "set", - "p": "flag_pw", - "pt": "global", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 610, - "y": 1260, - "wires": [ - [] - ] - }, - { - "id": "04cc2467807d2d6b", - "type": "change", - "z": "1613373abaf77a2c", - "name": "flag_pw false", - "rules": [ - { - "t": "set", - "p": "flag_pw", - "pt": "global", - "to": "false", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 390, - "y": 1260, + "id": "c1c044f3c2139f68", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "msg.enabled = false\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 490, + "y": 1140, "wires": [ - [] + [ + "579f2211199fd6ab" + ] ] }, { - "id": "12f1399b240830bf", - "type": "exec", - "z": "1613373abaf77a2c", - "command": " v4l2-ctl --list-formats-ext", - "addpay": "", - "append": "", - "useSpawn": "true", - "timer": "", - "winHide": false, - "oldrc": false, - "name": "check cam", - "x": 190, - "y": 100, + "id": "1daf9e3a5bd5ab48", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "msg", + "func": "global.set('flag_pw', true)\nglobal.set('flag', false)\nmsg.enabled = true\nreturn msg\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 430, + "y": 1040, "wires": [ [ - "6222f781629c72e7" - ], - [ - "6222f781629c72e7" - ], - [] + "fb13752beddee9f2" + ] ] }, { - "id": "6222f781629c72e7", + "id": "6d15f717d5a11002", "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\ncontent = '--READY--'\n\nif (msg.payload.includes('Cannot open device')){\n content = 'no camera found'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return msg\n }\n });\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "disable", + "func": "msg.enabled = false\nmsg.payload = false\nglobal.set(\"flag\",true)\n\nreturn msg\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 350, - "y": 100, + "x": 280, + "y": 1000, "wires": [ [ - "e89c16809f8a5f1c" + "e9b13dfd9f8d3711" ] ] }, { - "id": "e978bf8c53d1f15a", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "Settings internal cam", - "info": "", - "x": 120, + "id": "9a6b30a0175a8ecd", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "Routine", + "func": "from OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\n\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/picam2_switch_mode?mode=1')\n\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\n\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nenable_endstop = load_bool('rotor_enable_endstop')\n\nif enable_endstop:\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nautofocus = load_bool('cam_autofocus') ##change##\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\n##change##\nif focus_min == focus_max or autofocus:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef focus(f):\n ##change##\n if autofocus:\n camera('/picam2_af')\n else:\n camera('/picam2_focus?focus=' + str(f))\n ##change##\n\ndef photo(counter2):\n camera('/picam2_take_photo')\n ##change##\n focus(focuslist[returning[0]])\n if returning[0] < len(focuslist) - 1:\n returning[0] += 1\n else:\n returning[0] = 0\n ##change##\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\n\ndef stack_photo(i):\n\n camera('/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n\ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n ##change##\n focus(focuslist[i+1])\n else:\n camera(focuslist[0])\n sleep(1.7)\n\ndef photo_stack():\n camera(focuslist[0])\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n\n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n\n focus_thread.start()\n photo_thread.start()\n\n focus_thread.join()\n photo_thread.join()\n\n\ndef move_motor(enable_endstop=False):\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n\n motorrun('tt',tt_angle,enable_endstop)\n motorrun('rotor',rotor_angle,enable_endstop)\n return\n\n # THE FOLLOWING DOES NOT WORK PROPERLY WITH THREADING ?!\n\n #tt_thread = threading.Thread(target=motorrun, args=('tt', tt_angle))\n #rotor_thread = threading.Thread(target=motorrun, args=('rotor', rotor_angle))\n #tt_thread.start()\n #rotor_thread.start()\n #tt_thread.join()\n #rotor_thread.join()\n\n\ncounter2 = 0\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor(enable_endstop)\n sleep(load_float(\"cam_delay_before\"))\n\n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\n\nsystem('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nreturn msg\n", + "outputs": 1, + "x": 300, + "y": 1040, + "wires": [ + [ + "1daf9e3a5bd5ab48", + "795c85ad4f109567" + ] + ] + }, + { + "id": "afe47a9eaae6f67f", + "type": "ui_text", + "z": "481edaf6db5a7a54", + "group": "365a30d0dfa83e95", + "order": 1, + "width": 7, + "height": 1, + "name": "", + "label": "Current Status:", + "format": " {{msg.payload}} ", + "layout": "row-spread", + "className": "", + "x": 340, "y": 40, "wires": [] }, { - "id": "ccb7da246de908d1", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "preview internal cam", - "info": "", - "x": 110, - "y": 1160, - "wires": [] + "id": "8608517d0567d63f", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadS", + "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 40, + "wires": [ + [ + "afe47a9eaae6f67f" + ] + ] }, { - "id": "e9566588c5e40637", - "type": "inject", - "z": "1613373abaf77a2c", - "name": "4s/0.5", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } + "id": "6bf8344af427a6ba", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start status", + "links": [ + "6c6ef2255a7d39e5" ], - "repeat": "0.5", - "crontab": "", - "once": true, - "onceDelay": "4", - "topic": "Repeat", - "payload": "0.2", - "payloadType": "str", - "x": 80, - "y": 1220, + "x": 55, + "y": 40, + "wires": [ + [ + "8608517d0567d63f" + ] + ] + }, + { + "id": "78cfe60013a1bea4", + "type": "ui_switch", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Sharpness", + "tooltip": "", + "group": "ac7409105cfecac6", + "order": 2, + "width": 7, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 350, + "y": 380, "wires": [ [ - "95439678bb2df2a2" + "9774e7ad3b506354" ] ] }, { - "id": "14f9617b5b301318", + "id": "9774e7ad3b506354", "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Take Preview Shot", - "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\nsleep(0.5)\n\n\nstatus = load_str('status_internal_cam')\ncam=load_str('camera')\n\n\nif msg['flag'] == False and not 'Routine' in status:\n return msg\n\nif cam == 'external':\n return\n\nmsg['payload']=\"/tmp/preview.jpg?ts=\"+str(int(time()*10))\n\nif cam == 'gphoto' and status == 'no camera found':\n if camera('/gphoto_init') == 200:\n save('status_internal_cam','--READY--')\n\nif status!=\"--READY--\":\n return msg\n\nmsg['cropx'] = load_int('cam_cropx')\nmsg['cropy'] = load_int('cam_cropy')\nmsg['rotation'] = load_int('cam_rotation')\nmsg['filepath_in'] = 'tmp/tmp.jpg'\nmsg['filepath_out'] = 'tmp/preview.jpg'\nmsg['filepath'] = 'tmp/tmp.jpg'\nmsg['preview'] = True\n\nif cam == 'gphoto':\n if camera('/gphoto_test', msg) != 200:\n save('status_internal_cam','no camera found')\n return msg\n camera('/gphoto_preview', msg)\n\nif cam in ('usb_webcam', 'imx219','ov5647','imx477','imx290a','imx290b','imx378','ov9281','imx519'):\n take_photo('tmp/tmp.jpg')\n\ncamera('/crop',msg)\n\nreturn msg\n", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_sharparea',msg['payload'])\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", "outputs": 1, - "x": 410, - "y": 1220, + "x": 510, + "y": 380, "wires": [ [ - "948a3ae4444685f2", - "991b587d406d0d91", - "8f5d87ce24c40b11" + "f0af909f3e739b22" ] ] }, { - "id": "991b587d406d0d91", + "id": "39c744466a21735e", "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "ce9cc9d915dc6eb6", - "name": "preview_internal", - "order": 1, - "width": 12, - "height": 12, - "format": "
\n\n\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_min", + "order": 3, + "width": 7, + "height": 1, + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, "templateScope": "local", "className": "", - "x": 620, - "y": 1220, + "x": 990, + "y": 40, "wires": [ - [] + [ + "fa181d22775c2ce6" + ] ] }, { - "id": "1118d0965ff7c40b", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 3, - "width": 3, + "id": "61aab497fa50898e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "90223f7ddc082321", + "name": "focus_max", + "order": 4, + "width": 7, "height": 1, - "name": "projectname", - "label": "Projectname", - "format": "", - "layout": "row-left", + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", "className": "", - "x": 670, - "y": 500, - "wires": [] + "x": 990, + "y": 80, + "wires": [ + [ + "c615034ea6b26174" + ] + ] }, { - "id": "82c8ad50ecfbc755", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 11, - "width": 3, + "id": "5e83b653850fa16e", + "type": "ui_template", + "z": "481edaf6db5a7a54", + "group": "ac7409105cfecac6", + "name": "stacksize", + "order": 4, + "width": 7, "height": 1, - "name": "ringlight", - "label": "Ringlight", - "format": "", - "layout": "row-left", + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "storeOutMessages": true, + "fwdInMessages": true, + "resendOnRefresh": true, + "templateScope": "local", "className": "", - "x": 660, - "y": 700, - "wires": [] + "x": 320, + "y": 480, + "wires": [ + [ + "237c2135cdad86ea" + ] + ] }, { - "id": "33d94a04b96a2de0", + "id": "dd7fb8791d34c751", "type": "function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "enable", - "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found' || data.substring(0,5) === 'Featu'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", + "func": "global.set('light', 1)\nmsg.light = 1\nreturn msg\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 960, + "x": 250, + "y": 880, "wires": [ [ - "579f2211199fd6ab", - "c433515042ba01b5" + "180476141c2a44ad" ] ] }, { - "id": "c1c044f3c2139f68", + "id": "5baf89a2682265f7", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "enable led", + "links": [ + "eb1a2387a1eeea76" + ], + "x": 145, + "y": 880, + "wires": [ + [ + "dd7fb8791d34c751" + ] + ] + }, + { + "id": "6a26e8a7253d708c", "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.enabled = false\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 810, - "y": 1000, + "x": 830, + "y": 40, "wires": [ [ - "579f2211199fd6ab", - "c433515042ba01b5" + "39c744466a21735e" ] ] }, { - "id": "9a368472a72fbc48", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "preview arducam with focus", - "info": "", - "x": 140, - "y": 1360, - "wires": [] + "id": "35ad7e55833836c1", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "loadF", + "func": "var file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 830, + "y": 80, + "wires": [ + [ + "61aab497fa50898e" + ] + ] }, { - "id": "8f5d87ce24c40b11", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "preview_arducam", - "order": 2, - "width": 10, - "height": 12, - "format": "
\n\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 630, - "y": 1300, + "id": "9fd259de91de1da1", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 735, + "y": 40, "wires": [ - [] + [ + "6a26e8a7253d708c", + "35ad7e55833836c1" + ] + ] + }, + { + "id": "fa181d22775c2ce6", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_min'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});\n", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 40, + "wires": [ + [ + "ae5ee8787145906d" + ] + ] + }, + { + "id": "c615034ea6b26174", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "rate", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_focus_max'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n return msg\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1150, + "y": 80, + "wires": [ + [ + "ae5ee8787145906d" + ] ] }, { - "id": "282efe64332193c8", + "id": "ae5ee8787145906d", "type": "python3-function", - "z": "1613373abaf77a2c", + "z": "481edaf6db5a7a54", "name": "focus", - "func": "from OpenScan import load_str\n\nif load_str('camera') != 'imx519':\n return\n\nfrom Arducam import Focuser\n\n\nif msg['focuser'] == True:\n focuser = Focuser('/dev/v4l-subdev1')\n focuser.write(msg['focus'])\n return msg", + "func": "from OpenScan import camera\ncamera('/picam2_focus?focus=' + str(msg['payload']))\n\nreturn msg", "outputs": 1, - "x": 1110, - "y": 1460, + "x": 1290, + "y": 60, "wires": [ [] ] }, { - "id": "64b16ef47ab6d859", + "id": "f0af909f3e739b22", "type": "ui_switch", - "z": "1613373abaf77a2c", - "name": "MF", - "label": "", + "z": "481edaf6db5a7a54", + "name": "", + "label": "Show Features", "tooltip": "", - "group": "90223f7ddc082321", - "order": 4, - "width": 1, + "group": "ac7409105cfecac6", + "order": 1, + "width": 7, "height": 1, "passthru": true, "decouple": "false", "topic": "topic", "topicType": "msg", "style": "", - "onvalue": "false", + "onvalue": "true", "onvalueType": "bool", "onicon": "", "oncolor": "", - "offvalue": "true", + "offvalue": "false", "offvalueType": "bool", "officon": "", "offcolor": "", "animate": false, "className": "", - "x": 150, - "y": 1400, + "x": 340, + "y": 420, + "wires": [ + [ + "710fc2dbb5ef0167" + ] + ] + }, + { + "id": "710fc2dbb5ef0167", + "type": "python3-function", + "z": "481edaf6db5a7a54", + "name": "focus", + "func": "from OpenScan import save\nsave('cam_features',msg['payload'])\n\n\nif not 'flag' in msg:\n msg['flag'] = True\n msg['payload'] = False\n return msg", + "outputs": 1, + "x": 510, + "y": 420, "wires": [ [ - "f017f67a8d4a3750" + "78cfe60013a1bea4" ] ] }, { - "id": "f017f67a8d4a3750", + "id": "d93c2b67bcf23b9a", "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "let fs = global.get('fs');\nfilepath = '/home/pi/OpenScan/settings/';\n\nvar file = 'status_internal_cam'\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data != '--READY--'){\n return\n}\n\nfile = 'cam_AFmode'\ncontent = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});\n\nglobal.set('AF',msg.payload)\nmsg.enabled = false\nif (msg.payload == false){\n msg.enabled = true\n}\nif (msg.payload == true){\n file = 'cam_focus1'\n content = String(0)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n file = 'cam_focus2'\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n \n file = 'cam_stacksize'\n content = String(2)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n global.set('focus1', 0)\n global.set('focus2', 0)\n\n}\n\n\nmsg.focus = global.get('focus')\nmsg.payload = 'down'\nreturn msg", + "z": "481edaf6db5a7a54", + "name": "loadI", + "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 1400, + "x": 190, + "y": 480, "wires": [ [ - "5c39bd09.702d84", - "74521cf72050b515", - "b70e8c24ee011258", - "a2ff9dfd858821bc", - "ef62086d10d830fd" + "5e83b653850fa16e" ] ] }, { - "id": "65145c939b6647e2", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 55, - "y": 1400, - "wires": [ - [ - "64b16ef47ab6d859" - ] + "id": "237c2135cdad86ea", + "type": "function", + "z": "481edaf6db5a7a54", + "name": "write", + "func": "const delay = 100; // 100 ms delay\n\nif (!context.timeout) {\n context.timeout = setTimeout(() => {\n node.send({ payload: msg.payload });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n} else {\n context.set(\"lastMessage\", msg.payload);\n clearTimeout(context.timeout);\n context.timeout = setTimeout(() => {\n node.send({ payload: context.get(\"lastMessage\") });\n clearTimeout(context.timeout);\n delete context.timeout;\n }, delay);\n}\nvar file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 470, + "y": 480, + "wires": [ + [] ] }, { - "id": "5ea18678.975138", - "type": "trigger", - "z": "1613373abaf77a2c", - "name": "20ms", - "op1": "", - "op2": "0", - "op1type": "pay", - "op2type": "str", - "duration": "-20", - "extend": false, - "overrideDelay": false, - "units": "ms", - "reset": "", - "bytopic": "all", - "topic": "topic", - "outputs": 1, - "x": 730, - "y": 1440, + "id": "fd0258418489839d", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "start routine settings", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 95, + "y": 480, "wires": [ [ - "fd93843e238cc9ce" + "2d5b1eb4380ae5a8", + "d93c2b67bcf23b9a" ] ] }, { - "id": "5c39bd09.702d84", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "F+", - "order": 8, - "width": 1, - "height": 1, - "format": " ", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 410, - "y": 1400, + "id": "c6f281351e11b58a", + "type": "inject", + "z": "481edaf6db5a7a54", + "name": "", + "props": [ + { + "p": "enabled", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 600, "wires": [ [ - "dcfb5cce.0431a" + "ed2974731fb8a84e" ] ] }, { - "id": "dcfb5cce.0431a", - "type": "switch", - "z": "1613373abaf77a2c", + "id": "ca4ca7fae36d312d", + "type": "inject", + "z": "481edaf6db5a7a54", "name": "", - "property": "payload", - "propertyType": "msg", - "rules": [ - { - "t": "eq", - "v": "1", - "vt": "num" - }, + "props": [ { - "t": "eq", - "v": "-1", - "vt": "num" + "p": "enabled", + "v": "false", + "vt": "bool" }, { - "t": "eq", - "v": "up", + "p": "topic", "vt": "str" } ], - "checkall": "true", - "repair": false, - "outputs": 3, - "x": 550, - "y": 1420, + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 190, + "y": 640, "wires": [ [ - "5ea18678.975138", - "f4a41b1e7b221486" - ], - [ - "5ea18678.975138", - "f4a41b1e7b221486" - ], - [ - "8cdd0a6b.40bcd8" + "ed2974731fb8a84e" ] ] }, { - "id": "8cdd0a6b.40bcd8", - "type": "change", - "z": "1613373abaf77a2c", - "name": "", - "rules": [ - { - "t": "set", - "p": "reset", - "pt": "msg", - "to": "true", - "tot": "bool" - } + "id": "c8b93b42c720b9cf", + "type": "link in", + "z": "481edaf6db5a7a54", + "name": "sharpness/features", + "links": [ + "200d4b9951b6e066", + "e9b13dfd9f8d3711", + "fb13752beddee9f2" ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 560, - "y": 1480, + "x": 85, + "y": 380, "wires": [ [ - "5ea18678.975138", - "e9b3837b1ffb0360" + "78cfe60013a1bea4" ] ] }, { - "id": "74521cf72050b515", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "F-", - "order": 9, - "width": 1, - "height": 1, - "format": " ", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 410, - "y": 1440, + "id": "795c85ad4f109567", + "type": "debug", + "z": "481edaf6db5a7a54", + "name": "debug 5", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 620, + "y": 1000, + "wires": [] + }, + { + "id": "ea54fcc2.cfcc2", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "get dirs", + "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "outputs": 1, + "x": 480, + "y": 180, + "wires": [ + [ + "f3662f8c7d3d7a2d", + "01e4783e148c6698" + ] + ] + }, + { + "id": "2f4c0f98.dee2", + "type": "link in", + "z": "80a3942785a26c29", + "name": "filelist", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "a4f09e25.02569", + "ed35109311335099", + "fb13752beddee9f2" + ], + "x": 355, + "y": 220, "wires": [ [ - "dcfb5cce.0431a" + "ea54fcc2.cfcc2" ] ] }, { - "id": "7219f62c9fdc6753", + "id": "952ce286.4ffd4", "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 7, - "width": 2, + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 4, + "width": 6, "height": 1, - "name": "", - "label": "{{msg.payload}}", - "format": "", - "layout": "col-center", + "name": "Status", + "label": "Status", + "format": "{{msg.status}}", + "layout": "row-spread", "className": "", - "x": 1130, - "y": 1420, + "x": 250, + "y": 60, "wires": [] }, { - "id": "b70e8c24ee011258", - "type": "function", - "z": "1613373abaf77a2c", - "name": "global", - "func": "if (msg.payload == 'down'){\n msg.enabled = false\n msg.payload = ' '\n msg.focuser = global.get('focuser')\n return msg\n}\n\n\nmsg.enabled = true\n\nsign = msg.payload\nfocus = global.get('focus')\nif (focus > 3000){\n focusstep = 5\n}\nelse if (focus <=3000 && focus > 2000){\n focusstep = 3\n}\nelse{\n focusstep = 2\n}\n\n\nfocus = focus + sign * focusstep\n\nsign = msg.payload\nif (focus > 4000){\n distance = 6\n focus = 4000\n}\nelse if (focus > 1200 && focus <= 4000){\n distance = 737086 * Math.pow(focus, -1.4096)\n}\nelse if (focus <= 1200){\n distance = 999\n if (focus <=0){\n focus = 0\n }\n}\n\n\nglobal.set('focus', focus)\nmsg.focus = focus\nmsg.distance = distance\ndistance = distance * 10\nmsg.focuser = global.get('focuser')\nmsg.payload = String(distance.toFixed(1)) + 'mm'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 970, - "y": 1440, + "id": "d4383424.7807c8", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "upload", + "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", + "outputs": 2, + "x": 530, + "y": 460, "wires": [ [ - "7219f62c9fdc6753", - "282efe64332193c8", - "704a9f89089d1f25" + "9a132ab1.b21658" + ], + [ + "3d16b3789632784d", + "9a132ab1.b21658" ] ] }, { - "id": "f4a41b1e7b221486", + "id": "50710948.71c308", "type": "change", - "z": "1613373abaf77a2c", - "name": "focuser f", + "z": "80a3942785a26c29", + "name": "set", "rules": [ { "t": "set", - "p": "focuser", + "p": "set", "pt": "global", - "to": "false", - "tot": "bool" + "to": "payload", + "tot": "msg" } ], "action": "", @@ -2737,21 +2773,41 @@ "from": "", "to": "", "reg": false, - "x": 740, - "y": 1400, + "x": 750, + "y": 180, "wires": [ - [] + [ + "ada1b6f7cccc9344", + "85839a17fb7b58b9" + ] ] }, { - "id": "e9b3837b1ffb0360", + "id": "834046a4.647938", + "type": "ui_text", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "order": 5, + "width": 6, + "height": 1, + "name": "Set", + "label": "Set:", + "format": "{{msg.payload.Name}}", + "layout": "row-spread", + "className": "", + "x": 750, + "y": 220, + "wires": [] + }, + { + "id": "9a132ab1.b21658", "type": "change", - "z": "1613373abaf77a2c", - "name": "focuser t", + "z": "80a3942785a26c29", + "name": "flag.true", "rules": [ { "t": "set", - "p": "focuser", + "p": "flag", "pt": "global", "to": "true", "tot": "bool" @@ -2762,841 +2818,850 @@ "from": "", "to": "", "reg": false, - "x": 740, - "y": 1480, + "x": 780, + "y": 460, "wires": [ - [] + [ + "8689e938.dd9e38" + ] ] }, { - "id": "fd93843e238cc9ce", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "10ms", - "pauseType": "delay", - "timeout": "20", - "timeoutUnits": "milliseconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": false, - "allowrate": false, + "id": "3c67e97b.9d19a6", + "type": "function", + "z": "80a3942785a26c29", + "name": "enable", + "func": "//if (global.get('flag') === false){\n// msg.enabled = false\n// msg.color=\"white\"\n//}\n//else{\n\n msg.enabled = true\n msg.color=\"red\"\n \n//}\n\nreturn msg", "outputs": 1, - "x": 850, - "y": 1440, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 130, + "y": 340, "wires": [ [ - "b70e8c24ee011258" + "7a93d1e18254685c", + "e434ef42bd6b92e8", + "d5d840183025d91b", + "ab9e90ab5a53a0dd", + "478994f671a3907d" ] ] }, { - "id": "25c4138bddb77b6b", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "set", - "order": 10, - "width": 2, - "height": 1, - "format": "set", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 570, - "y": 1540, + "id": "bfc01f26.c32cf", + "type": "change", + "z": "80a3942785a26c29", + "name": "flag.false", + "rules": [ + { + "t": "set", + "p": "flag", + "pt": "global", + "to": "false", + "tot": "bool" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 420, + "y": 500, "wires": [ [ - "95e1d239988b29e0" + "f20f2dbc.0f123" ] ] }, { - "id": "95e1d239988b29e0", - "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "focus = global.get('focus')\nfocus1 = global.get('focus1')\nfocus2 = global.get('focus2')\nlet fs = global.get('fs');\nfilepath = '/home/pi/OpenScan/settings/';\n \nif (msg.payload == false){\n return msg\n}\n\nif (focus1 != 0 && focus2 != 0){\n global.set('focus1', 0)\n global.set('focus2', 0)\n file = 'cam_focus1'\n content = String(0)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n file = 'cam_focus2'\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n msg.distance1 = ' '\n msg.distance2 = ' '\n msg.enabled = false\n return msg\n}\n\nif (focus > 4000){\n distance = 6\n focus = 4000\n}\nelse if (focus > 1200 && focus <= 4000){\n distance = 737086 * Math.pow(focus, -1.4096)\n}\nelse if (focus <= 1200){\n distance = 999.9\n if (focus <=0){\n focus = 0\n }\n}\ndistance = distance * 10\n\nif (focus1 == 0){\n global.set('focus1', focus)\n file = 'cam_focus1'\n content = String(focus)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n global.set('distance1', distance)\n msg.distance1 = distance.toFixed(1)\n msg.distance2 = 'tbd'\n msg.enabled = false\n return msg\n}\nif (focus1 != 0 && focus2 ==0 && focus!= focus1){\n global.set('focus2', focus)\n file = 'cam_focus2'\n content = String(focus)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n global.set('distance2', distance)\n msg.distance1 = global.get('distance1').toFixed(1)\n msg.distance2 = distance.toFixed(1)\n msg.enabled = true\n return msg\n}\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 710, - "y": 1560, + "id": "b33d604c.5f1a6", + "type": "link in", + "z": "80a3942785a26c29", + "name": "enable cloud", + "links": [ + "4082b136.dae18", + "8689e938.dd9e38", + "bd75f33b8a57c522", + "e9b13dfd9f8d3711", + "f20f2dbc.0f123", + "fb13752beddee9f2" + ], + "x": 35, + "y": 340, "wires": [ [ - "7889245e91ddea4b", - "210ef5246d1a8790" + "3c67e97b.9d19a6" ] ] }, { - "id": "7889245e91ddea4b", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 11, - "width": 2, - "height": 1, - "name": "", - "label": "{{msg.distance1}}", - "format": "{{msg.distance2}}", - "layout": "col-center", - "className": "", - "x": 830, - "y": 1600, - "wires": [] - }, - { - "id": "a1d29e56599da0bd", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "focusnumber", - "links": [ - "210ef5246d1a8790", - "2dd2503d7ab0214b", - "6b94bf2295b1b31d" + "id": "f6bd1a04.470838", + "type": "change", + "z": "80a3942785a26c29", + "name": "set", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "set", + "tot": "global" + } ], - "x": 175, - "y": 1760, + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 410, + "y": 460, "wires": [ [ - "06504f47ee1744d7", - "5f8b90ef08a7d68c" + "d4383424.7807c8" ] ] }, { - "id": "210ef5246d1a8790", + "id": "4082b136.dae18", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "links": [ + "b33d604c.5f1a6", + "87574a42938afec4" + ], + "x": 715, + "y": 140, + "wires": [] + }, + { + "id": "f20f2dbc.0f123", "type": "link out", - "z": "1613373abaf77a2c", + "z": "80a3942785a26c29", "name": "", "mode": "link", "links": [ - "a1d29e56599da0bd", "8367cfa0bf5bc5df", + "b33d604c.5f1a6", "149e2e46b9623a2d" ], - "x": 835, - "y": 1560, + "x": 515, + "y": 500, "wires": [] }, { - "id": "b6f37e23f2491639", - "type": "ui_switch", - "z": "1613373abaf77a2c", - "name": "Stack", - "label": "", - "tooltip": "", - "group": "90223f7ddc082321", - "order": 6, - "width": 1, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "topic", - "topicType": "msg", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 290, - "y": 1600, - "wires": [ - [ - "2d66216fee29250c" - ] - ] - }, - { - "id": "a2ff9dfd858821bc", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "msg.payload = false\nif (msg.enabled == false){\n return msg\n}\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 410, - "y": 1560, - "wires": [ - [ - "25c4138bddb77b6b", - "7889245e91ddea4b", - "4cfada2de1c5bb74", - "95e1d239988b29e0" - ] - ] + "id": "8689e938.dd9e38", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "8367cfa0bf5bc5df", + "b33d604c.5f1a6", + "149e2e46b9623a2d" + ], + "x": 875, + "y": 460, + "wires": [] }, { - "id": "2d66216fee29250c", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "file = 'cam_STmode'\nlet fs = global.get('fs');\nfilepath = '/home/pi/OpenScan/settings/';\ncontent = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});\n\nmsg.enabled = true\nglobal.set('ST',msg.payload)\nif (msg.payload == false){\n global.set('focus1',0)\n global.set('focus2',0)\n file = 'cam_focus1'\n content = String(0)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n file = 'cam_focus2'\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n \n \n msg.enabled = false\n}\nreturn msg\n", + "id": "15de0ebb.616d61", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 430, - "y": 1600, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 380, "wires": [ [ - "25c4138bddb77b6b", - "7889245e91ddea4b", - "2dd2503d7ab0214b", - "4cfada2de1c5bb74" + "a7d89487.ee8858" ] ] }, { - "id": "ef62086d10d830fd", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "msg.payload = false\nreturn msg", + "id": "a7d89487.ee8858", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 150, - "y": 1560, + "x": 690, + "y": 380, "wires": [ [ - "b6f37e23f2491639", - "523019d0a2c698f5" + "a4f09e25.02569" ] ] }, { - "id": "06504f47ee1744d7", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 12, - "width": 2, - "height": 1, + "id": "a4f09e25.02569", + "type": "link out", + "z": "80a3942785a26c29", "name": "", - "label": "Stacksize:", - "format": "{{msg.stacksize}}", - "layout": "row-center", - "className": "", - "x": 710, - "y": 1760, + "mode": "link", + "links": [ + "2f4c0f98.dee2" + ], + "x": 775, + "y": 360, "wires": [] }, { - "id": "2dd2503d7ab0214b", + "id": "7a93d1e18254685c", "type": "link out", - "z": "1613373abaf77a2c", + "z": "80a3942785a26c29", "name": "", "mode": "link", "links": [ - "a1d29e56599da0bd" + "809c9427e14e2448", + "92c98e6ce7cd25f9" ], - "x": 535, - "y": 1620, + "x": 235, + "y": 500, "wires": [] }, { - "id": "21306d6402225553", - "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.stacksize = msg.payload\nmsg.enabled = true\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 550, - "y": 1720, + "id": "4d99c601c9881680", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "refresh", + "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", + "outputs": 2, + "x": 320, + "y": 180, "wires": [ [ - "06504f47ee1744d7", - "ca184d58f7deb4b1", - "84608db962fd9932" + "ea54fcc2.cfcc2", + "b42e061fb1f1f3d7" + ], + [ + "6434e713f088012b" ] ] }, { - "id": "e2f8fdd47bdd1b66", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "stacksize", - "label": " ", - "tooltip": "", - "group": "90223f7ddc082321", - "order": 13, - "width": 2, - "height": 1, - "passthru": true, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "2", - "max": "20", - "step": "1", - "className": "", - "x": 400, - "y": 1720, + "id": "372e95797a3f2f3b", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "limit :)", + "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", + "outputs": 1, + "x": 90, + "y": 220, "wires": [ [ - "21306d6402225553" + "573edbfdb7500ddc" ] ] }, { - "id": "523019d0a2c698f5", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 5, - "width": 1, - "height": 1, + "id": "573edbfdb7500ddc", + "type": "delay", + "z": "80a3942785a26c29", "name": "", - "label": "St", - "format": "", - "layout": "col-center", - "className": "", - "x": 290, - "y": 1560, - "wires": [] - }, - { - "id": "dfbfe28bac5c4221", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 3, - "width": 1, - "height": 1, - "name": "MF", - "label": "MF", - "format": "", - "layout": "col-center", - "className": "", - "x": 150, - "y": 1440, - "wires": [] - }, - { - "id": "ca184d58f7deb4b1", - "type": "function", - "z": "1613373abaf77a2c", - "name": "save", - "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.stacksize)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 690, - "y": 1720, - "wires": [ - [] - ] - }, - { - "id": "704a9f89089d1f25", - "type": "function", - "z": "1613373abaf77a2c", - "name": "save", - "func": "var file = 'cam_focus'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.focus)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 1110, - "y": 1500, - "wires": [ - [] - ] - }, - { - "id": "5f8b90ef08a7d68c", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'cam_stacksize'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "pauseType": "rate", + "timeout": "5", + "timeoutUnits": "seconds", + "rate": "1", + "nbRateUnits": "1", + "rateUnits": "second", + "randomFirst": "1", + "randomLast": "5", + "randomUnits": "seconds", + "drop": false, + "allowrate": false, "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 1720, + "x": 230, + "y": 220, "wires": [ [ - "e2f8fdd47bdd1b66" + "c46e10b9c201913e" ] ] }, { - "id": "4cfada2de1c5bb74", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "if (msg.enabled == true){\n msg.enabled = false\n}\nelse{\n msg.enabled = true\n}\nreturn msg\n", + "id": "dacb1f078b624e10", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 570, - "y": 1660, + "ok": "No", + "cancel": "Yes", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 550, + "y": 340, "wires": [ [ - "84608db962fd9932" + "c8d65cc7c2ff7c36" ] ] }, { - "id": "84608db962fd9932", - "type": "link out", - "z": "1613373abaf77a2c", + "id": "92c98e6ce7cd25f9", + "type": "link in", + "z": "80a3942785a26c29", "name": "", - "mode": "link", "links": [ - "8367cfa0bf5bc5df", - "149e2e46b9623a2d" + "7a93d1e18254685c", + "bd75f33b8a57c522" ], - "x": 675, - "y": 1660, - "wires": [] + "x": 35, + "y": 180, + "wires": [ + [ + "c46e10b9c201913e" + ] + ] }, { - "id": "e89c16809f8a5f1c", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "gphoto", - "func": "\nfrom OpenScan import camera, save, load_str\n\nif load_str('camera') == 'gphoto':\n if camera('/gphoto_init') == 200:\n if camera('/gphoto_test') == 200:\n save('status_internal_cam','--READY--')\n return msg\nif load_str('camera') == 'external':\n save('status_internal_cam','--READY--')", + "id": "3d16b3789632784d", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, "outputs": 1, - "x": 490, - "y": 100, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 770, + "y": 500, "wires": [ [] ] }, { - "id": "917a194be245384a", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable projectname", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 540, + "id": "6434e713f088012b", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "Terms", + "x": 470, + "y": 220, "wires": [ - [ - "f4b3112a9ec6c487" - ] + [] ] }, { - "id": "65cef204b16f8741", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable shutter", - "links": [ - "2d76e5617f13cd6c", - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 580, + "id": "c8d65cc7c2ff7c36", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "del", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", + "outputs": 1, + "x": 690, + "y": 340, "wires": [ [ - "84d6b96c8ebaac96" + "a4f09e25.02569" ] ] }, { - "id": "2aea1727dbea76ce", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable cropx", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 620, + "id": "f4e9a4bd79b4221f", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 340, "wires": [ [ - "9c6b48b7b4cc4e1a" + "dacb1f078b624e10" ] ] }, { - "id": "4f212b44aa487945", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable cropy", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 660, + "id": "2806bf08ea21216d", + "type": "function", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 380, "wires": [ [ - "c470fd0b15356206" + "15de0ebb.616d61" ] ] }, { - "id": "6d1e12f51f9af0b6", + "id": "61990987acd0f263", "type": "link in", - "z": "1613373abaf77a2c", - "name": "start camchk", + "z": "80a3942785a26c29", + "name": "", "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" + "6c6ef2255a7d39e5" ], - "x": 55, - "y": 100, + "x": 45, + "y": 60, "wires": [ [ - "12f1399b240830bf" + "51579603bce21e98" ] ] }, { - "id": "8ebd1dcb5db156ed", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 2, - "width": 6, + "id": "e8e488a6dd5d0b33", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "Download", + "order": 8, + "width": 3, "height": 1, - "name": "", - "label": "Current Status:", - "format": " {{msg.payload}} ", - "layout": "row-spread", + "format": "\n
Download\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", "className": "", - "x": 320, - "y": 160, - "wires": [] + "x": 880, + "y": 260, + "wires": [ + [] + ] }, { - "id": "94a7aec739f9266b", + "id": "0c387c0291d6c131", "type": "function", - "z": "1613373abaf77a2c", - "name": "loadS", - "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", + "z": "80a3942785a26c29", + "name": "msg", + "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 160, + "x": 750, + "y": 260, "wires": [ [ - "8ebd1dcb5db156ed" + "e8e488a6dd5d0b33" ] ] }, { - "id": "2415272f42ce468c", + "id": "e5f38b4a07a5e278", "type": "link in", - "z": "1613373abaf77a2c", - "name": "start status", + "z": "80a3942785a26c29", + "name": "", "links": [ - "6c6ef2255a7d39e5" + "960912e90ba5b5bc", + "50eeb3e362f9027f" ], - "x": 55, - "y": 160, + "x": 655, + "y": 220, "wires": [ [ - "94a7aec739f9266b" + "834046a4.647938" ] ] }, { - "id": "a1e14624058e74cd", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "start routine settings", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 55, - "y": 500, + "id": "e434ef42bd6b92e8", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "upload2", + "order": 7, + "width": 3, + "height": 1, + "format": "upload", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 460, "wires": [ [ - "f4b3112a9ec6c487", - "107a030938cbfea9", - "84d6b96c8ebaac96", - "9c6b48b7b4cc4e1a", - "c470fd0b15356206", - "9e30e33a1520fee0", - "79ecb889f7113405" + "f6bd1a04.470838" ] ] }, { - "id": "1daf9e3a5bd5ab48", + "id": "c46e10b9c201913e", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "refresh", + "order": 2, + "width": 4, + "height": 1, + "format": "refresh{{msg.text}}", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 160, + "y": 180, + "wires": [ + [ + "372e95797a3f2f3b", + "4d99c601c9881680" + ] + ] + }, + { + "id": "d5d840183025d91b", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del set", + "order": 11, + "width": 2, + "height": 1, + "format": "delete set", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 380, + "wires": [ + [ + "2806bf08ea21216d" + ] + ] + }, + { + "id": "ab9e90ab5a53a0dd", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "del ", + "order": 10, + "width": 2, + "height": 1, + "format": "delete all", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 270, + "y": 340, + "wires": [ + [ + "f4e9a4bd79b4221f" + ] + ] + }, + { + "id": "478994f671a3907d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "combine", + "order": 9, + "width": 2, + "height": 1, + "format": "combine", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 280, + "y": 540, + "wires": [ + [ + "51bfd0fb7b1d292e" + ] + ] + }, + { + "id": "189c1eed09624a7b", "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "global.set('flag_pw', true)\nglobal.set('flag', true)\nmsg.enabled = true\nreturn msg\n", + "z": "80a3942785a26c29", + "name": "combine", + "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 810, - "y": 920, + "x": 280, + "y": 580, "wires": [ [ - "fb13752beddee9f2" + "1493398979a63775" ] ] }, { - "id": "6d15f717d5a11002", + "id": "51bfd0fb7b1d292e", "type": "function", - "z": "1613373abaf77a2c", - "name": "disable", - "func": "msg.enabled = false\nreturn msg\n", + "z": "80a3942785a26c29", + "name": "combine", + "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 300, - "y": 840, + "x": 420, + "y": 540, "wires": [ - [ - "e9b13dfd9f8d3711" - ] + [] ] }, { - "id": "d14bbbb446d45e39", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "preview", - "links": [ - "f20da2fc4978b7bf" - ], - "x": 135, - "y": 1260, + "id": "da325be8e74179be", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "combine", + "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", + "outputs": 1, + "x": 560, + "y": 580, "wires": [ [ - "95439678bb2df2a2" + "ed35109311335099" ] ] }, { - "id": "db7eea74d3bf892b", + "id": "ed35109311335099", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "809c9427e14e2448", + "2f4c0f98.dee2" + ], + "x": 655, + "y": 580, + "wires": [] + }, + { + "id": "1493398979a63775", "type": "ui_toast", - "z": "1613373abaf77a2c", + "z": "80a3942785a26c29", "position": "dialog", "displayTime": "3", "highlight": "", "sendall": true, "outputs": 1, - "ok": "Finish", - "cancel": "2nd pass", - "raw": false, + "ok": "OK", + "cancel": "Cancel", + "raw": true, "className": "", "topic": "", - "name": "", - "x": 510, - "y": 880, + "name": "Combine", + "x": 420, + "y": 580, "wires": [ [ - "0b8661103366f834" + "da325be8e74179be" ] ] }, { - "id": "0b8661103366f834", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "continue", - "func": "from os import system\nfrom os.path import isfile\n\n\nif msg['payload'] == '2nd pass':\n msg['enabled'] = True\n return msg,None\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp/tmp.jpg'\nzippath = basepath + 'tmp/tmp.zip'\nprojectcode = msg['projectcode']\n\nsystem('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')\n\nmsg['path'] = basepath + 'scans/' + projectcode + '.zip'\n\nif isfile(zippath):\n system('rm ' + zippath)\n\nreturn None, msg", - "outputs": 2, - "x": 660, - "y": 920, + "id": "ada1b6f7cccc9344", + "type": "link out", + "z": "80a3942785a26c29", + "name": "combine", + "mode": "link", + "links": [ + "6dd356510c446cf4" + ], + "x": 835, + "y": 180, + "wires": [] + }, + { + "id": "6dd356510c446cf4", + "type": "link in", + "z": "80a3942785a26c29", + "name": "combine", + "links": [ + "ada1b6f7cccc9344" + ], + "x": 175, + "y": 580, "wires": [ [ - "431f917c2541ae48", - "579f2211199fd6ab", - "c433515042ba01b5" - ], - [ - "1daf9e3a5bd5ab48", - "579f2211199fd6ab", - "c433515042ba01b5" + "189c1eed09624a7b" ] ] }, { - "id": "79ecb889f7113405", + "id": "b42e061fb1f1f3d7", + "type": "link out", + "z": "80a3942785a26c29", + "name": "", + "mode": "link", + "links": [ + "397ab7f44b893c89", + "3876d5cbd248592b" + ], + "x": 435, + "y": 140, + "wires": [] + }, + { + "id": "b99505440832439f", "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "inactive", - "func": "from requests import get\nfrom OpenScan import load_int\n\ntimeout = load_int('timeout_ringlight')\n\nmsg['cmd'] = 'get'\n\ntry:\n flask = 'http://127.0.0.1:1312/ping'\n r = get(flask, params=msg)\n\n idle = float(r.text.split(\":\")[1].split('}')[0])\n\n msg['payload'] = idle\n\n if idle > timeout:\n return msg,msg\nexcept:\n pass\n\nreturn None,msg", - "outputs": 2, - "x": 200, - "y": 740, + "z": "80a3942785a26c29", + "name": "diskspace", + "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", + "outputs": 1, + "x": 800, + "y": 100, "wires": [ [ - "9e30e33a1520fee0" - ], - [ - "8d7e04531c34f349" + "92047434f8e9f927" ] ] }, { - "id": "8d7e04531c34f349", + "id": "92047434f8e9f927", + "type": "ui_toast", + "z": "80a3942785a26c29", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 950, + "y": 100, + "wires": [ + [] + ] + }, + { + "id": "f3662f8c7d3d7a2d", "type": "delay", - "z": "1613373abaf77a2c", + "z": "80a3942785a26c29", "name": "", - "pauseType": "delay", - "timeout": "30", + "pauseType": "rate", + "timeout": "5", "timeoutUnits": "seconds", "rate": "1", "nbRateUnits": "1", - "rateUnits": "second", + "rateUnits": "minute", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", - "drop": false, + "drop": true, "allowrate": false, "outputs": 1, - "x": 200, - "y": 780, + "x": 650, + "y": 100, "wires": [ [ - "79ecb889f7113405" + "b99505440832439f" ] ] }, { - "id": "c433515042ba01b5", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "pause", - "group": "7aaf184330605300", - "order": 22, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-pause", - "payload": " ", - "payloadType": "str", - "topic": "Scan paused", - "topicType": "str", - "x": 810, - "y": 1040, + "id": "51579603bce21e98", + "type": "python3-function", + "z": "80a3942785a26c29", + "name": "read", + "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", + "outputs": 1, + "x": 130, + "y": 60, "wires": [ [ - "63db399d8ac2acb6" + "952ce286.4ffd4" ] ] }, { - "id": "63db399d8ac2acb6", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "pause", - "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nif status == 'Routine-paused':\n save('status_internal_cam', 'Routine-continue')\nelse:\n save('status_internal_cam', 'Routine-paused')", - "outputs": 1, - "x": 930, - "y": 1040, + "id": "9a5baae623355f9d", + "type": "ui_template", + "z": "80a3942785a26c29", + "group": "db43d646.2074c8", + "name": "preview", + "order": 6, + "width": 6, + "height": 6, + "format": "
\n\n\n
\n", + "storeOutMessages": false, + "fwdInMessages": false, + "resendOnRefresh": false, + "templateScope": "local", + "className": "", + "x": 1020, + "y": 220, "wires": [ [] ] }, { - "id": "44c598049cd533fd", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "crop", - "links": [ - "f358de1e64b491bb" - ], - "x": 595, - "y": 640, - "wires": [ - [ - "fecf5cff888bb570", - "0ee4950bd21498bd" - ] - ] - }, - { - "id": "ea54fcc2.cfcc2", + "id": "85839a17fb7b58b9", "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "get dirs", - "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\nfrom datetime import datetime\nfrom PIL import Image\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n \n if not os.path.isfile(directory + 'preview/' + os.path.basename(d)[:-4]+'.jpg'):\n image = f.open(f.namelist()[int(photos/2)])\n img = Image.open(image)\n width, height = img.size\n width_factor = width/300\n height_factor = height/295\n if height_factor>=width_factor and height_factor > 1:\n new_size=(int(width/height_factor), int(height/height_factor))\n img = img.resize(new_size)\n elif height_factor 1:\n new_size=(int(width/width_factor),int(height/width_factor))\n img = img.resize(new_size)\n img.save(directory + 'preview/' + os.path.basename(d)[:-4] +'.jpg')\n list=[]\n for fi in f.filelist:\n list.append(f.getinfo(fi.filename).date_time)\n \n duration = str(datetime(*max(list)) - datetime(*min(list)))\n \n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \"Duration\":duration,\n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \"Duration\":duration,\n\n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", + "z": "80a3942785a26c29", + "name": "preview", + "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", "outputs": 1, - "x": 480, - "y": 180, - "wires": [ - [ - "b9a3a0f9.bcbea", - "f3662f8c7d3d7a2d" - ] - ] - }, - { - "id": "2f4c0f98.dee2", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "filelist", - "links": [ - "960912e90ba5b5bc", - "a4f09e25.02569", - "ed35109311335099", - "fb13752beddee9f2", - "50eeb3e362f9027f" - ], - "x": 355, - "y": 140, + "x": 880, + "y": 220, "wires": [ [ - "ea54fcc2.cfcc2" + "9a5baae623355f9d" ] ] }, { - "id": "b9a3a0f9.bcbea", + "id": "01e4783e148c6698", "type": "ui_table", - "z": "4981d84ef1a366d1", + "z": "80a3942785a26c29", "group": "b5fdd57b.15eda8", "name": "", "order": 1, @@ -3670,1151 +3735,151 @@ "y": 180, "wires": [ [ - "50710948.71c308", "4082b136.dae18", + "50710948.71c308", "834046a4.647938", "0c387c0291d6c131" ] ] }, { - "id": "952ce286.4ffd4", - "type": "ui_text", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", + "id": "cb3437ec113e1b6f", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "SSH", + "tooltip": "", + "group": "4390b2ebcbbe104c", "order": 3, "width": 6, "height": 1, - "name": "Status", - "label": "Status", - "format": "{{msg.status}}", - "layout": "row-spread", + "passthru": true, + "decouple": "false", + "topic": "", + "topicType": "str", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, "className": "", - "x": 250, - "y": 60, - "wires": [] - }, - { - "id": "d4383424.7807c8", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "upload", - "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\nfrom subprocess import getoutput\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n pid = getoutput('pidof curl')\n if pid != \"\":\n os.system('kill ' + pid)\n\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", - "outputs": 2, - "x": 530, - "y": 460, + "x": 390, + "y": 360, "wires": [ [ - "9a132ab1.b21658" - ], - [ - "3d16b3789632784d", - "9a132ab1.b21658" + "c24f61b87e3226dd" ] ] }, { - "id": "50710948.71c308", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "set", - "rules": [ - { - "t": "set", - "p": "set", - "pt": "global", - "to": "payload", - "tot": "msg" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 750, - "y": 180, + "id": "60fd0adce1cfeb82", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Samba", + "tooltip": "", + "group": "4390b2ebcbbe104c", + "order": 4, + "width": 6, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "test2", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 400, + "y": 400, "wires": [ [ - "ada1b6f7cccc9344", - "85839a17fb7b58b9" + "441d3ef525e901da" ] ] }, { - "id": "834046a4.647938", - "type": "ui_text", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "order": 4, + "id": "c24f61b87e3226dd", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "ssh", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", + "outputs": 1, + "x": 530, + "y": 360, + "wires": [ + [] + ] + }, + { + "id": "c013e836e759a085", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "4390b2ebcbbe104c", + "order": 2, "width": 6, "height": 1, - "name": "Set", - "label": "Set:", - "format": "{{msg.payload.Name}}", - "layout": "row-spread", + "passthru": false, + "label": "Terms Of Use", + "tooltip": "", + "color": "", + "bgcolor": "", "className": "", - "x": 750, - "y": 220, - "wires": [] - }, - { - "id": "9a132ab1.b21658", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "flag.true", - "rules": [ - { - "t": "set", - "p": "flag", - "pt": "global", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 780, - "y": 460, + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 120, + "y": 320, "wires": [ [ - "8689e938.dd9e38" + "b78346ca3ce70c68" ] ] }, { - "id": "3c67e97b.9d19a6", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "enable", - "func": "if (global.get('flag') === false){\n msg.enabled = false\n msg.color=\"white\"\n}\nelse{\n msg.enabled = true\n msg.color=\"red\"\n \n}\n\nreturn msg", + "id": "f0d8dbcca76a1926", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 130, - "y": 340, + "ok": "Agree", + "cancel": "Disagree", + "raw": true, + "className": "", + "topic": "", + "name": "", + "x": 410, + "y": 320, "wires": [ [ - "7a93d1e18254685c", - "e434ef42bd6b92e8", - "d5d840183025d91b", - "ab9e90ab5a53a0dd", - "478994f671a3907d" + "e95b86cbac1b03b9" ] ] }, { - "id": "bfc01f26.c32cf", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "flag.false", - "rules": [ - { - "t": "set", - "p": "flag", - "pt": "global", - "to": "false", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 420, - "y": 500, - "wires": [ - [ - "f20f2dbc.0f123" - ] - ] - }, - { - "id": "b33d604c.5f1a6", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "enable cloud", - "links": [ - "4082b136.dae18", - "8689e938.dd9e38", - "bd75f33b8a57c522", - "e9b13dfd9f8d3711", - "f20f2dbc.0f123", - "fb13752beddee9f2" - ], - "x": 35, - "y": 340, - "wires": [ - [ - "3c67e97b.9d19a6" - ] - ] - }, - { - "id": "f6bd1a04.470838", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "set", - "rules": [ - { - "t": "set", - "p": "payload", - "pt": "msg", - "to": "set", - "tot": "global" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 410, - "y": 460, - "wires": [ - [ - "d4383424.7807c8" - ] - ] - }, - { - "id": "4082b136.dae18", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "b33d604c.5f1a6", - "87574a42938afec4" - ], - "x": 715, - "y": 140, - "wires": [] - }, - { - "id": "f20f2dbc.0f123", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "b33d604c.5f1a6", - "149e2e46b9623a2d" - ], - "x": 515, - "y": 500, - "wires": [] - }, - { - "id": "8689e938.dd9e38", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "b33d604c.5f1a6", - "149e2e46b9623a2d" - ], - "x": 875, - "y": 460, - "wires": [] - }, - { - "id": "15de0ebb.616d61", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 550, - "y": 380, - "wires": [ - [ - "a7d89487.ee8858" - ] - ] - }, - { - "id": "a7d89487.ee8858", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "del", - "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", - "outputs": 1, - "x": 690, - "y": 380, - "wires": [ - [ - "a4f09e25.02569" - ] - ] - }, - { - "id": "a4f09e25.02569", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "2f4c0f98.dee2", - "c20357dd.374108", - "e9aab326.a6896", - "edd22cc7.befe1", - "19b81967.49db87", - "8ee1b3bb.7b0b3", - "d5246b3cc796afc6" - ], - "x": 775, - "y": 360, - "wires": [] - }, - { - "id": "7a93d1e18254685c", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "809c9427e14e2448", - "92c98e6ce7cd25f9" - ], - "x": 235, - "y": 500, - "wires": [] - }, - { - "id": "4d99c601c9881680", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "refresh", - "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if i == 'preview':\n continue\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", - "outputs": 2, - "x": 320, - "y": 180, - "wires": [ - [ - "ea54fcc2.cfcc2", - "b42e061fb1f1f3d7" - ], - [ - "6434e713f088012b" - ] - ] - }, - { - "id": "372e95797a3f2f3b", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "limit :)", - "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", - "outputs": 1, - "x": 90, - "y": 220, - "wires": [ - [ - "573edbfdb7500ddc" - ] - ] - }, - { - "id": "573edbfdb7500ddc", - "type": "delay", - "z": "4981d84ef1a366d1", - "name": "", - "pauseType": "rate", - "timeout": "5", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": false, - "allowrate": false, - "outputs": 1, - "x": 230, - "y": 220, - "wires": [ - [ - "c46e10b9c201913e" - ] - ] - }, - { - "id": "dacb1f078b624e10", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 550, - "y": 340, - "wires": [ - [ - "c8d65cc7c2ff7c36" - ] - ] - }, - { - "id": "92c98e6ce7cd25f9", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "7a93d1e18254685c", - "bd75f33b8a57c522" - ], - "x": 35, - "y": 180, - "wires": [ - [ - "c46e10b9c201913e" - ] - ] - }, - { - "id": "3d16b3789632784d", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "Terms", - "x": 770, - "y": 500, - "wires": [ - [] - ] - }, - { - "id": "6434e713f088012b", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "Terms", - "x": 470, - "y": 220, - "wires": [ - [] - ] - }, - { - "id": "c8d65cc7c2ff7c36", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "del", - "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if os.path.isdir(dir + i):\n shutil.rmtree(dir + i)\n else:\n os.remove(dir + i)\n\nreturn msg", - "outputs": 1, - "x": 690, - "y": 340, - "wires": [ - [ - "a4f09e25.02569" - ] - ] - }, - { - "id": "f4e9a4bd79b4221f", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "msg", - "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 410, - "y": 340, - "wires": [ - [ - "dacb1f078b624e10" - ] - ] - }, - { - "id": "2806bf08ea21216d", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "msg", - "func": "msg.Set=global.get('set')['Set']\nmsg.payload = 'Are you sure to delete ' + msg.Set + '?'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 410, - "y": 380, - "wires": [ - [ - "15de0ebb.616d61" - ] - ] - }, - { - "id": "61990987acd0f263", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "6c6ef2255a7d39e5" - ], - "x": 45, - "y": 60, - "wires": [ - [ - "51579603bce21e98" - ] - ] - }, - { - "id": "e8e488a6dd5d0b33", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "Download", - "order": 6, - "width": 3, - "height": 1, - "format": "\n
Download\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 880, - "y": 260, - "wires": [ - [] - ] - }, - { - "id": "0c387c0291d6c131", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "msg", - "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 750, - "y": 260, - "wires": [ - [ - "e8e488a6dd5d0b33" - ] - ] - }, - { - "id": "e5f38b4a07a5e278", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 655, - "y": 220, - "wires": [ - [ - "834046a4.647938" - ] - ] - }, - { - "id": "e434ef42bd6b92e8", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "upload2", - "order": 7, - "width": 3, - "height": 1, - "format": "upload", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 280, - "y": 460, - "wires": [ - [ - "f6bd1a04.470838", - "bfc01f26.c32cf" - ] - ] - }, - { - "id": "c46e10b9c201913e", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "refresh", - "order": 1, - "width": 3, - "height": 1, - "format": "refresh{{msg.text}}", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 160, - "y": 180, - "wires": [ - [ - "372e95797a3f2f3b", - "4d99c601c9881680" - ] - ] - }, - { - "id": "d5d840183025d91b", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "del set", - "order": 9, - "width": 2, - "height": 1, - "format": "delete set", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 270, - "y": 380, - "wires": [ - [ - "2806bf08ea21216d" - ] - ] - }, - { - "id": "ab9e90ab5a53a0dd", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "del ", - "order": 10, - "width": 2, - "height": 1, - "format": "delete all", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 270, - "y": 340, - "wires": [ - [ - "f4e9a4bd79b4221f" - ] - ] - }, - { - "id": "478994f671a3907d", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "combine", - "order": 8, - "width": 2, - "height": 1, - "format": "combine", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 280, - "y": 540, - "wires": [ - [ - "51bfd0fb7b1d292e" - ] - ] - }, - { - "id": "189c1eed09624a7b", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "combine", - "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 280, - "y": 580, - "wires": [ - [ - "1493398979a63775" - ] - ] - }, - { - "id": "51bfd0fb7b1d292e", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "combine", - "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 420, - "y": 540, - "wires": [ - [] - ] - }, - { - "id": "da325be8e74179be", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "combine", - "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','writing ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", - "outputs": 1, - "x": 560, - "y": 580, - "wires": [ - [ - "ed35109311335099" - ] - ] - }, - { - "id": "ed35109311335099", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "809c9427e14e2448", - "2f4c0f98.dee2" - ], - "x": 655, - "y": 580, - "wires": [] - }, - { - "id": "1493398979a63775", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": true, - "className": "", - "topic": "", - "name": "Combine", - "x": 420, - "y": 580, - "wires": [ - [ - "da325be8e74179be" - ] - ] - }, - { - "id": "ada1b6f7cccc9344", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "combine", - "mode": "link", - "links": [ - "6dd356510c446cf4" - ], - "x": 835, - "y": 180, - "wires": [] - }, - { - "id": "6dd356510c446cf4", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "combine", - "links": [ - "ada1b6f7cccc9344" - ], - "x": 175, - "y": 580, - "wires": [ - [ - "189c1eed09624a7b" - ] - ] - }, - { - "id": "b42e061fb1f1f3d7", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "397ab7f44b893c89" - ], - "x": 435, - "y": 140, - "wires": [] - }, - { - "id": "b99505440832439f", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "diskspace", - "func": "from subprocess import getoutput\nfrom OpenScan import load_int\n\ndiskspace_threshold = load_int('diskspace_threshold')\n\ndiskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n\navailable = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n\n\nif available < diskspace_threshold:\n msg['topic'] = 'Low diskspace remaining! ('+str(available)+'MB)' \n msg['payload'] = 'Please delete some/all locally stored files.'\n msg['color'] = 'red'\n return msg\n", - "outputs": 1, - "x": 800, - "y": 100, - "wires": [ - [ - "92047434f8e9f927" - ] - ] - }, - { - "id": "92047434f8e9f927", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 950, - "y": 100, - "wires": [ - [] - ] - }, - { - "id": "f3662f8c7d3d7a2d", - "type": "delay", - "z": "4981d84ef1a366d1", - "name": "", - "pauseType": "rate", - "timeout": "5", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "minute", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "allowrate": false, - "outputs": 1, - "x": 650, - "y": 100, - "wires": [ - [ - "b99505440832439f" - ] - ] - }, - { - "id": "51579603bce21e98", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "read", - "func": "from OpenScan import load_str\nfrom os import listdir, path\n\nstatus = load_str('status_cloud')\n\nif status[0:9] == 'uploading':\n progress = load_str('status_uploadprogress')[-6:]\n if progress[-1:] == '%':\n status = status + ' (' + progress + ')'\n\nif status[0:7] == 'zipping':\n path1 = '/home/pi/OpenScan/tmp/split/'\n files = listdir(path1)\n size1 = 0\n for file in files:\n size1 += path.getsize(path1+file)\n size2 = path.getsize('/home/pi/OpenScan/scans/'+ files[0][:-2])\n \n status = 'zipping files (' + str(float(int(1000*size1/size2))/10) + '%)'\n\nmsg['status'] = status\nreturn msg\n", - "outputs": 1, - "x": 130, - "y": 60, - "wires": [ - [ - "952ce286.4ffd4" - ] - ] - }, - { - "id": "9a5baae623355f9d", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "preview", - "order": 5, - "width": 6, - "height": 6, - "format": "
\n\n\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 1020, - "y": 220, - "wires": [ - [] - ] - }, - { - "id": "85839a17fb7b58b9", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "preview", - "func": "from time import time\nimport os\n\npath = '/home/pi/OpenScan/scans/preview/'\nimage = os.path.basename(msg['payload']['Set'])[:-4] +'.jpg'\n\nmsg['payload']=\"/scans/preview/\" + image +\"?ts=\"+str(int(time()*10))\nreturn msg", - "outputs": 1, - "x": 880, - "y": 220, - "wires": [ - [ - "9a5baae623355f9d" - ] - ] - }, - { - "id": "45058bfcf047e8cc", - "type": "inject", - "z": "4981d84ef1a366d1", - "name": "", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "", - "payloadType": "date", - "x": 100, - "y": 120, - "wires": [ - [] - ] - }, - { - "id": "40dee936a9abac0d", - "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "SSH", - "tooltip": "", - "group": "4fe6b4c0ade0938a", - "order": 3, - "width": 6, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "", - "topicType": "str", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 390, - "y": 340, - "wires": [ - [ - "dc354c54078ca607" - ] - ] - }, - { - "id": "4fd9bb53fdb51a25", - "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Samba", - "tooltip": "", - "group": "4fe6b4c0ade0938a", - "order": 4, - "width": 6, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "test2", - "topicType": "msg", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 400, - "y": 380, - "wires": [ - [ - "b0aa8ffae5a3578a" - ] - ] - }, - { - "id": "dc354c54078ca607", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "ssh", - "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('ssh'):\n save('ssh', state)\n\nif state == True:\n os.system('/etc/init.d/ssh start')\nelse:\n os.system('/etc/init.d/ssh stop')", - "outputs": 1, - "x": 530, - "y": 340, - "wires": [ - [] - ] - }, - { - "id": "52858b4eceacc902", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "", - "group": "4fe6b4c0ade0938a", - "order": 2, - "width": 6, - "height": 1, - "passthru": false, - "label": "Terms Of Use", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 120, - "y": 300, - "wires": [ - [ - "f99ec8781a33ec7d" - ] - ] - }, - { - "id": "595153429adef33b", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Wifi", - "group": "0fe66c9190b8a87c", - "order": 1, - "width": 6, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Network Settings

Hostname

The device can be accessed through any browser in the same network. Therefore, you can either enter the device's IP address or the given hostname. The standard name is 'openscan' but it is highly recommended to change the name, when using multiple devices (e.g. 'openscan1', 'openscan2' ...)

Select Wifi

After booting, the device will automatically search for available wireless networks and create a list. You can connect to a given network by entering the wifi password and country code. To find the right two-character country code, see the following list: ISO 3166 Country Code on Wikipedia

Search Wifi

You can manually refresh the list of available networks by pressing this button.

Reset Wifi

Delete the list of known wireless networks (and passwords) and reset the default. After this step, you will either need to use Ethernet or a modified wpa_supplicant.conf file. (see glennklockwood.com for more details about the wpa_supplicant.conf file, which has to be manually created and placed into the /boot/ directory of the sd-card)

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 590, - "y": 120, - "wires": [ - [ - "f304680180a23479" - ] - ] - }, - { - "id": "7dc39bd847d16ded", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "Agree", - "cancel": "Disagree", - "raw": true, - "className": "", - "topic": "", - "name": "", - "x": 410, - "y": 300, - "wires": [ - [ - "5f849178998d9082" - ] - ] - }, - { - "id": "02858034e17b827f", + "id": "34374044c0030625", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "General", - "group": "4fe6b4c0ade0938a", + "group": "4390b2ebcbbe104c", "order": 1, "width": 6, "height": 1, @@ -4830,19 +3895,19 @@ "topic": "topic", "topicType": "msg", "x": 740, - "y": 240, + "y": 220, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "675d4933a44ae6b5", + "id": "b2b6bf23c9989133", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Pinout", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 1, "width": 6, "height": 1, @@ -4858,219 +3923,32 @@ "topic": "topic", "topicType": "msg", "x": 430, - "y": 200, + "y": 220, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "b0aa8ffae5a3578a", + "id": "441d3ef525e901da", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "smb", "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('smb'):\n save('smb', state)\nif state == True:\n os.system('/etc/init.d/smbd start')\nelse:\n os.system('/etc/init.d/smbd stop')\n\n\n", "outputs": 1, "x": 530, - "y": 380, - "wires": [ - [] - ] - }, - { - "id": "cc3cb10f2ea3f8b8", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "blink Light1", - "func": "import RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nfrom OpenScan import ringlight\nfrom time import sleep\n\ndelay = 0.1\nringlight(2,False)\n\nfor i in range (5):\n ringlight(1,True)\n sleep(delay)\n ringlight(1,False)\n sleep(delay)", - "outputs": 1, - "x": 290, - "y": 760, - "wires": [ - [] - ] - }, - { - "id": "d114f4d4d7f31981", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "reboot", - "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", - "outputs": 1, - "x": 270, - "y": 720, + "y": 400, "wires": [ [] ] }, { - "id": "79181ad3b56d5c62", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "4fe6b4c0ade0938a", - "order": 7, - "width": 2, - "height": 1, - "name": "", - "label": "Model", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 730, - "y": 620, - "wires": [] - }, - { - "id": "4d81bd138733c410", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "4fe6b4c0ade0938a", - "order": 9, - "width": 2, - "height": 1, - "name": "", - "label": "Camera", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 840, - "y": 420, - "wires": [] - }, - { - "id": "80b579a4220e5c23", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "model", - "label": "", - "tooltip": "", - "place": "Select option", - "group": "4fe6b4c0ade0938a", - "order": 8, - "width": 4, - "height": 1, - "passthru": true, - "multiple": false, - "options": [ - { - "label": "Please Select", - "value": "None", - "type": "str" - }, - { - "label": "OpenScan Mini", - "value": "OSMini", - "type": "str" - }, - { - "label": "OpenScan Classic", - "value": "OSClassic", - "type": "str" - } - ], - "payload": "", - "topic": "topic", - "topicType": "msg", - "className": "", - "x": 390, - "y": 620, - "wires": [ - [ - "896242c5a7e50fa7" - ] - ] - }, - { - "id": "a2c1dba3e67be015", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "Camera", - "label": "", - "tooltip": "", - "place": "Select option", - "group": "4fe6b4c0ade0938a", - "order": 10, - "width": 4, - "height": 1, - "passthru": true, - "multiple": false, - "options": [ - { - "label": "Pi Cam v1 - 5mp", - "value": "ov5647", - "type": "str" - }, - { - "label": "Pi Cam v2 - 8mp", - "value": "imx219", - "type": "str" - }, - { - "label": "Pi Cam HQ - 12.3mp", - "value": "imx477", - "type": "str" - }, - { - "label": "Arducam IMX519 - 16mp", - "value": "imx519", - "type": "str" - }, - { - "label": "IMX290 a", - "value": "imx290a", - "type": "str" - }, - { - "label": "IMX290 b", - "value": "imx290b", - "type": "str" - }, - { - "label": "IMX378", - "value": "imx378", - "type": "str" - }, - { - "label": "OV9281", - "value": "ov9281", - "type": "str" - }, - { - "label": "DSLR (gphoto)", - "value": "gphoto", - "type": "str" - }, - { - "label": "USB Webcam", - "value": "usb_webcam", - "type": "str" - }, - { - "label": "External Camera", - "value": "external", - "type": "str" - } - ], - "payload": "", - "topic": "topic", - "topicType": "msg", - "className": "", - "x": 400, - "y": 420, - "wires": [ - [ - "4058a31e942e8f95", - "6d68cccec646e0a0" - ] - ] - }, - { - "id": "9cf5d56263caada7", + "id": "3256bab150113a48", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Motor", - "group": "d49a6dfd7fb17096", + "group": "7a3279eea439bcdd", "order": 1, "width": 6, "height": 1, @@ -5086,19 +3964,19 @@ "topic": "topic", "topicType": "msg", "x": 430, - "y": 120, + "y": 140, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "72238e6a01d1152c", + "id": "7a186669a17daa71", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "camera", - "group": "93aadb71dee6d977", + "group": "d324f0b852c2df0a", "order": 1, "width": 6, "height": 1, @@ -5114,71 +3992,41 @@ "topic": "topic", "topicType": "msg", "x": 420, - "y": 160, + "y": 180, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "15a0a2f431ce55c3", + "id": "edac7dd292e7e486", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "General Settings", "info": "", "x": 120, - "y": 260, + "y": 280, "wires": [] }, { - "id": "87a403b9a09aa38d", + "id": "161b52034e578ee2", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Network", "info": "", "x": 100, - "y": 880, + "y": 720, "wires": [] }, { - "id": "896242c5a7e50fa7", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "model", - "func": "from OpenScan import load_str, save\n\nstate = msg['payload']\nmsg['state'] = state\n\nif state != load_str('model'):\n save('model', state)\n if state == 'OSMini':\n save('rotor_stepsperrotation',48000)\n save('cam_rotation',90)\n save('rotor_anglemin',-70)\n save('rotor_anglemax',20)\n \n\n if state == 'OSClassic':\n save('rotor_stepsperrotation',17067)\n save('cam_rotation',0)\n save('rotor_anglemin',-30)\n save('rotor_anglemax',30)\n\nif state == \"OSMini\":\n msg['crop2'] = 'Crop X (%)'\n msg['crop1'] = 'Crop Y (%)'\nelif state == \"OSClassic\":\n msg['crop1'] = 'Crop X (%)'\n msg['crop2'] = 'Crop Y (%)'\n\nreturn msg", - "outputs": 1, - "x": 530, - "y": 620, - "wires": [ - [ - "f358de1e64b491bb" - ] - ] - }, - { - "id": "4058a31e942e8f95", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "camera", - "func": "from OpenScan import load_str, save\nfrom json import load\nstate = msg['payload']\nstate_old = load_str('camera')\n\nif state_old != state:\n save('camera',state)\n return msg", - "outputs": 1, - "x": 540, - "y": 500, - "wires": [ - [ - "34b685aff2080d31" - ] - ] - }, - { - "id": "c833f6243a059d83", + "id": "f6d6cc35679ede63", "type": "ui_switch", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "more sets", "label": "Advanced Settings", "tooltip": "", - "group": "4fe6b4c0ade0938a", + "group": "4390b2ebcbbe104c", "order": 5, "width": 6, "height": 1, @@ -5198,71 +4046,47 @@ "animate": false, "className": "", "x": 400, - "y": 660, + "y": 480, "wires": [ [ - "8be8015931c663cc" + "f06a7bcad524e9f9" ] ] }, { - "id": "15fd1c9e5610cb85", + "id": "29745a36fc157f3f", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "more sets", "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", "outputs": 2, "x": 820, - "y": 660, - "wires": [ - [ - "62cd775a1c02dac8" - ], - [ - "c833f6243a059d83" - ] - ] - }, - { - "id": "74c5c7cd2681045b", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "load camera&model", - "func": "from OpenScan import load_str, load_bool\n\nmodel = load_str('model')\ncamera = load_str('camera')\nupdate = load_bool('updateable')\nmsg['model'] = model\nmsg['camera'] = camera\nmsg2 = {}\nmsg3 = {}\nmsg4 = {}\n\nif camera in ('imx219','ov5647','imx477','imx290a','imx290b','imx378','ov9281','gphoto'):\n msg['payload'] = {\"group\":{\"hide\":[\"Scan_Arducam\"],\"show\":[\"Scan_Settings\",\"Scan_Picamera\"]}}\nelif camera in ('imx519'):\n msg['payload'] = {\"group\":{\"hide\":[\"Scan_Picamera\"],\"show\":[\"Scan_Settings\",\"Scan_Arducam\"]}}\nelif camera in ('external'):\n msg['payload'] = {\"group\":{\"hide\":[\"Scan_Arducam\",\"Scan_Picamera\"],\"show\":[\"Scan_Settings\"]}}\n\n\nif model == 'None' or model == '' or camera == 'None' or camera == '':\n msg2['payload']={\"tabs\": {\"hide\": [\"Scan\", \"Files&Cloud\",\"Settings\",\"Update & Info\"]}}\n msg3['payload'] = {\"group\":{\"hide\":[\"OpenScan_Home\"],\"show\":[\"OpenScan_Initialize\"]}}\nelse:\n msg2['payload']={\"tabs\": {\"show\": [\"Scan\", \"Files&Cloud\",\"Settings\",\"Update & Info\"]},\"hide\":{}}\n msg3['payload'] = {\"group\":{\"show\":[\"OpenScan_Home\"],\"hide\":[\"OpenScan_Initialize\"]}}\n\nif update == True:\n msg4['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg4['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\nreturn msg,msg2,msg3,msg4", - "outputs": 4, - "x": 340, - "y": 40, + "y": 480, "wires": [ [ - "b4db790aad28ba39" - ], - [ - "b4db790aad28ba39" - ], - [ - "b4db790aad28ba39" + "8750ad979e9ea246" ], [ - "b4db790aad28ba39" + "f6d6cc35679ede63" ] ] }, { - "id": "b4db790aad28ba39", + "id": "bf23328f9fb11b22", "type": "ui_ui_control", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "change visibility", "events": "all", "x": 600, - "y": 40, + "y": 60, "wires": [ [] ] }, { - "id": "eb8ccf2786ea3d63", + "id": "b37be1d222bc70c9", "type": "inject", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "1s_repeater", "props": [ { @@ -5281,60 +4105,62 @@ "payload": "", "payloadType": "date", "x": 150, - "y": 40, + "y": 60, "wires": [ [ - "74c5c7cd2681045b", - "9b756a1f9b0e7317" + "89eedf29b404f750" ] ] }, { - "id": "9b756a1f9b0e7317", + "id": "89eedf29b404f750", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "load advanced", - "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\nreturn msg", - "outputs": 1, - "x": 320, - "y": 80, + "func": "from OpenScan import load_bool\n\nif load_bool('advanced_settings') == False:\n msg['payload']={\"group\":{\"hide\":[\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\"]}}\nelse:\n msg['payload']={\"group\":{\"hide\":[],\"show\":[\"Settings_General\",\"Settings_Network\",\"Settings_OpenScanCloud\",\"Settings_Camera\",\"Settings_Motor\",\"Settings_Pinout\",]}}\n\nupdate = load_bool('updateable')\n\nmsg2 = {}\n\nif update == True:\n msg2['payload'] = {\"group\":{\"show\":[\"OpenScan_Update\"]}}\nelif update == False:\n msg2['payload'] = {\"group\":{\"hide\":[\"OpenScan_Update\"]}}\n\n\nreturn msg,msg2", + "outputs": 2, + "x": 360, + "y": 60, "wires": [ [ - "b4db790aad28ba39" + "bf23328f9fb11b22" + ], + [ + "bf23328f9fb11b22" ] ] }, { - "id": "ca4afadb5b21751f", + "id": "2050de5d9e02f69f", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Info Texts", "info": "", "x": 100, - "y": 120, + "y": 140, "wires": [] }, { - "id": "f393400.d87dcc", + "id": "ded3086945a6d4b5", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "check ip address", "func": "import socket\nimport subprocess\n\ntestIP = \"8.8.8.8\"\ns = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)\ns.connect((testIP, 0))\nipaddr = s.getsockname()[0]\nhost = socket.gethostname()\n\nmsg['ip']=ipaddr\n\nreturn msg", "outputs": 1, - "x": 410, - "y": 1060, + "x": 250, + "y": 940, "wires": [ [ - "bb789eed.9f73c" + "3cfe464506f46ecd" ] ] }, { - "id": "bb789eed.9f73c", + "id": "3cfe464506f46ecd", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "0fe66c9190b8a87c", - "order": 2, + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 1, "width": 0, "height": 0, "name": "", @@ -5342,299 +4168,26 @@ "format": "{{msg.ip}}", "layout": "row-spread", "className": "", - "x": 590, - "y": 1060, + "x": 430, + "y": 940, "wires": [] }, { - "id": "2a0f9919.4c9a86", + "id": "bd206ad109831e6a", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "OpenScanCloud", "info": "", "x": 120, - "y": 1240, + "y": 1260, "wires": [] }, { - "id": "27c6b221c90ed9e1", - "type": "exec", - "z": "017bd4e4a428bee5", - "command": "iwlist wlan0 scan | grep ESSID | sed 's/ESSID://g;s/\"//g;s/^ *//;s/ *$//'", - "addpay": false, - "append": "", - "useSpawn": "false", - "timer": "", - "winHide": false, - "oldrc": false, - "name": "scan", - "x": 250, - "y": 1040, - "wires": [ - [ - "b05cf92302a5c112", - "f393400.d87dcc" - ], - [ - "e9677b85856b5873" - ], - [] - ] - }, - { - "id": "b05cf92302a5c112", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "WIFI", - "func": "msg['options']=[]\n\nfor i in msg['payload'].split('\\n'):\n if i not in msg['options'] and i!=\"\":\n msg['options'].append(i)\n \nif len(msg['options']) != 0:\n msg['enabled']=True\n\nreturn msg", - "outputs": 1, - "x": 370, - "y": 1020, - "wires": [ - [ - "59c9f67283ba1709" - ] - ] - }, - { - "id": "da5ddaf4cc25b8c8", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "search", - "group": "0fe66c9190b8a87c", - "order": 4, - "width": 3, - "height": 1, - "passthru": false, - "label": "Search Wifi", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "true", - "payloadType": "bool", - "topic": "", - "topicType": "str", - "x": 90, - "y": 980, - "wires": [ - [ - "27c6b221c90ed9e1", - "51521bc6eb44cde5" - ] - ] - }, - { - "id": "59c9f67283ba1709", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "", - "label": "", - "tooltip": "", - "place": "Select Wifi", - "group": "0fe66c9190b8a87c", - "order": 3, - "width": 6, - "height": 1, - "passthru": true, - "multiple": false, - "options": [], - "payload": "", - "topic": "", - "topicType": "str", - "className": "", - "x": 520, - "y": 980, - "wires": [ - [ - "2bb52656f9554dab" - ] - ] - }, - { - "id": "b2d7d6a730f7dca6", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Reset Wifi", - "group": "0fe66c9190b8a87c", - "order": 5, - "width": 3, - "height": 1, - "passthru": false, - "label": "Reset Wifi", - "tooltip": "", - "color": "red", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "Delete all prior wifi connections? (You will need to reconnect to the OpenScan device by Ethernet or manually modify the wpa_supplicant.conf)", - "payloadType": "str", - "topic": "", - "topicType": "str", - "x": 110, - "y": 1140, - "wires": [ - [ - "78985ac6d3bcdf60" - ] - ] - }, - { - "id": "c3b8faac9ebb2c80", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "Reset Wifi", - "func": "from time import sleep\n\nif msg['payload']!=\"Yes\":\n return\n\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\nsleep(3)\nos.system('systemctl restart nodered')\nreturn msg", - "outputs": 1, - "x": 440, - "y": 1140, - "wires": [ - [] - ] - }, - { - "id": "78985ac6d3bcdf60", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 270, - "y": 1140, - "wires": [ - [ - "c3b8faac9ebb2c80" - ] - ] - }, - { - "id": "4f7f49b12c2d2572", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "add Wifi", - "func": "from time import sleep\nsleep(0.1)\n\nos.system('wpa_cli -i wlan0 reconfigure')\n\nreturn msg", - "outputs": 1, - "x": 1320, - "y": 1000, - "wires": [ - [] - ] - }, - { - "id": "ebcc98685059b9d4", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "password", - "x": 780, - "y": 980, - "wires": [ - [ - "68204a14528ab842" - ] - ] - }, - { - "id": "68204a14528ab842", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "if msg['payload'] == 'Cancel':\n return\n\nmsg['password'] = msg['payload']\nmsg['payload']='Enter country code (ISO 3166-1 alpha-2, see: Wikipedia)'\n\n\nreturn msg", - "outputs": 1, - "x": 910, - "y": 980, - "wires": [ - [ - "852edf901bdec9c5" - ] - ] - }, - { - "id": "852edf901bdec9c5", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "Save", - "cancel": "Cancel", - "raw": true, - "className": "", - "topic": "", - "name": "country", - "x": 1040, - "y": 980, - "wires": [ - [ - "1b09d634e3d9357b" - ] - ] - }, - { - "id": "1b09d634e3d9357b", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "modWPA", - "func": "if msg['payload'] == 'Cancel':\n return\n\nif len(msg['payload'])!=2:\n msg['payload'] = 'invalid country code'\n return msg,None\n\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\ntemp_dir = '/home/pi/OpenScan/tmp/wpa'\n\ncode = msg['payload'].upper()\nssid = msg['ssid']\npassword = msg['password']\n\nif len(code) != 2:\n msg['topic'] = 'ERROR'\n msg['payload'] = 'invalid country code (see ISO 3166-1 alpha-2)'\n return msg\n\nwith open(wpa_dir, 'r') as file:\n for i in file.readlines():\n if 'country=' in i:\n code_old=i.split('country=')[1][0:2]\n break\n\nwith open(wpa_dir, 'r') as file:\n wpa = file.read()\n if ssid in wpa:\n msg['topic'] = 'ERROR'\n msg['payload'] = 'Network already exists! If you have trouble connecting, please consider resetting the saved Wifi connections.'\n return msg\n wpa=wpa.replace('country=' + code_old, 'country=' + code)\n wpa=wpa + '\\nnetwork={\\n priority=10\\n ssid=\"'+ssid+'\"\\n psk=\"'+password+'\"\\n}\\n'\n\nwith open(temp_dir,'w+') as file:\n file.write(wpa)\nos.system('mv '+temp_dir + ' ' + wpa_dir)\n\nmsg['topic'] = 'Updating Wifi'\nmsg['payload'] = 'reconnecting might take a moment'\nreturn msg,msg\n", - "outputs": 2, - "x": 1180, - "y": 980, - "wires": [ - [ - "03732a7d3b0c95aa" - ], - [ - "4f7f49b12c2d2572" - ] - ] - }, - { - "id": "03732a7d3b0c95aa", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 1330, - "y": 960, - "wires": [ - [] - ] - }, - { - "id": "e97d17c6590138e2", + "id": "b70a9a665c1e4d36", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Cloud-settings", - "group": "3b4bd36726be16d5", + "group": "12b719cba49817c9", "order": 1, "width": 6, "height": 1, @@ -5649,19 +4202,19 @@ "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 620, - "y": 160, + "x": 740, + "y": 260, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "f7bf47e3eec6d736", + "id": "c9f0566601a3e130", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", "order": 4, "width": 0, "height": 0, @@ -5671,14 +4224,14 @@ "layout": "row-spread", "className": "", "x": 410, - "y": 1380, + "y": 1400, "wires": [] }, { - "id": "b52d91c628b151a4", + "id": "9bd86d27ea499a2a", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", "order": 5, "width": 0, "height": 0, @@ -5688,14 +4241,14 @@ "layout": "row-spread", "className": "", "x": 390, - "y": 1420, + "y": 1440, "wires": [] }, { - "id": "1969c709ef2fd1d5", + "id": "2c37f7030810d234", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", + "z": "e43a27722b508115", + "group": "12b719cba49817c9", "order": 3, "width": 0, "height": 0, @@ -5705,32 +4258,32 @@ "layout": "row-spread", "className": "", "x": 370, - "y": 1460, + "y": 1480, "wires": [] }, { - "id": "88e92b621d2a3394", + "id": "f40286c18afd4501", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "save", "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload']!=\"Yes\":\n return None,msg\n\ntry:\n r = OpenScanCloud('getTokenInfo', {'token':msg['token']})\n if r.status_code != 200:\n msg['payload'] = 'Could not verify token'\n return msg \n \n msg1 = r.json()\n \n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n msg1['enabled'] = True\nexcept:\n pass\n\nsave('token',msg['token'])\n \nmsg['payload'] = 'Token verified and saved'\nreturn msg, msg1", "outputs": 2, "x": 750, - "y": 1320, + "y": 1340, "wires": [ [ - "76acd48a511a5e3e", - "b01581296b94dfcd" + "455a5266017ea121", + "50f73cee213ec05c" ], [ - "9c51aa678f16980f" + "264eece408043021" ] ] }, { - "id": "76acd48a511a5e3e", + "id": "455a5266017ea121", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -5742,19 +4295,19 @@ "topic": "", "name": "", "x": 890, - "y": 1280, + "y": 1300, "wires": [ [] ] }, { - "id": "5f50ed3f6ba37cef", + "id": "c368df68593bc2bf", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "label": "Token", "tooltip": "", - "group": "3b4bd36726be16d5", + "group": "12b719cba49817c9", "order": 2, "width": 6, "height": 1, @@ -5766,69 +4319,69 @@ "className": "", "topicType": "str", "x": 350, - "y": 1340, + "y": 1360, "wires": [ [ - "cb62d30728af2968" + "18fd1afa768187b3" ] ] }, { - "id": "cb62d30728af2968", + "id": "18fd1afa768187b3", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Save?", "func": "msg['token'] = msg['payload']\n\nif len(msg['payload'])>=14:\n \n msg[\"payload\"]='Save and verify token: ' + msg['payload']\n return msg\nelse:\n return None,msg", "outputs": 2, "x": 470, - "y": 1340, + "y": 1360, "wires": [ [ - "94e503dd2e64d903" + "418aea2ec65573a0" ], [ - "d859bb39914d4999" + "9792c89c5f4429f9" ] ] }, { - "id": "0dd01eef6e70059e", + "id": "f90a98899b7a71d0", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "text", "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", "outputs": 1, "x": 230, - "y": 1340, + "y": 1360, "wires": [ [ - "5f50ed3f6ba37cef" + "c368df68593bc2bf" ] ] }, { - "id": "788fabff98c7973c", + "id": "b4c843620c251c43", "type": "link in", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "token", "links": [ "960912e90ba5b5bc", - "b01581296b94dfcd", - "d859bb39914d4999", + "50f73cee213ec05c", + "9792c89c5f4429f9", "50eeb3e362f9027f" ], "x": 75, - "y": 1340, + "y": 1360, "wires": [ [ - "0dd01eef6e70059e" + "f90a98899b7a71d0" ] ] }, { - "id": "94e503dd2e64d903", + "id": "418aea2ec65573a0", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -5841,75 +4394,75 @@ "topic": "", "name": "", "x": 610, - "y": 1320, + "y": 1340, "wires": [ [ - "88e92b621d2a3394" + "f40286c18afd4501" ] ] }, { - "id": "d859bb39914d4999", + "id": "9792c89c5f4429f9", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "mode": "link", "links": [ - "788fabff98c7973c" + "b4c843620c251c43" ], "x": 555, - "y": 1360, + "y": 1380, "wires": [] }, { - "id": "9c51aa678f16980f", + "id": "264eece408043021", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "links": [ "5d267acc10020091", - "397ab7f44b893c89" + "3876d5cbd248592b" ], "x": 835, - "y": 1360, + "y": 1380, "wires": [] }, { - "id": "397ab7f44b893c89", + "id": "3876d5cbd248592b", "type": "link in", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "OSCparameters", "links": [ "960912e90ba5b5bc", - "9c51aa678f16980f", + "264eece408043021", "b42e061fb1f1f3d7", "50eeb3e362f9027f" ], "x": 75, - "y": 1380, + "y": 1400, "wires": [ [ - "a7fd00943edc380b" + "5daca3ec47f8e7fc" ] ] }, { - "id": "b01581296b94dfcd", + "id": "50f73cee213ec05c", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "links": [ - "788fabff98c7973c", + "b4c843620c251c43", "5d267acc10020091" ], "x": 835, - "y": 1320, + "y": 1340, "wires": [] }, { - "id": "bf6d941ad307ce22", + "id": "95578e54a9b61cba", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "prompt", "displayTime": "3", "highlight": "", @@ -5922,35 +4475,35 @@ "topic": "", "name": "", "x": 250, - "y": 1520, + "y": 1540, "wires": [ [ - "f22dfef37d5de773" + "d7a5693da7855da8" ] ] }, { - "id": "f22dfef37d5de773", + "id": "d7a5693da7855da8", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", "outputs": 2, "x": 390, - "y": 1520, + "y": 1540, "wires": [ [ - "54602ee49ca022e7" + "2b02b97dd1614e52" ], [ - "1505f3e72f971081" + "183a629accb417b1" ] ] }, { - "id": "1505f3e72f971081", + "id": "183a629accb417b1", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -5963,15 +4516,15 @@ "topic": "", "name": "", "x": 530, - "y": 1560, + "y": 1580, "wires": [ [] ] }, { - "id": "54602ee49ca022e7", + "id": "2b02b97dd1614e52", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "prompt", "displayTime": "3", "highlight": "", @@ -5984,17 +4537,17 @@ "topic": "", "name": "", "x": 530, - "y": 1520, + "y": 1540, "wires": [ [ - "f9efcb87b74abbd4" + "3e4c15d7b538f816" ] ] }, { - "id": "510dbe4d76253bd6", + "id": "3bf622f344172721", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "prompt", "displayTime": "3", "highlight": "", @@ -6007,35 +4560,35 @@ "topic": "", "name": "", "x": 810, - "y": 1520, + "y": 1540, "wires": [ [ - "600b2306caed1640" + "e431cb2b8d217cee" ] ] }, { - "id": "600b2306caed1640", + "id": "e431cb2b8d217cee", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", "outputs": 1, "x": 950, - "y": 1520, + "y": 1540, "wires": [ [ - "bbad1ab5f8f63fb7" + "106874534890f229" ] ] }, { - "id": "d34cd203725bac15", + "id": "a38d7fde5c73210f", "type": "ui_button", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Register", - "group": "3b4bd36726be16d5", - "order": 7, + "group": "12b719cba49817c9", + "order": 6, "width": 2, "height": 1, "passthru": false, @@ -6050,17 +4603,17 @@ "topic": "Requesting an OpenScanCloud Token", "topicType": "str", "x": 100, - "y": 1520, + "y": 1540, "wires": [ [ - "bf6d941ad307ce22" + "95578e54a9b61cba" ] ] }, { - "id": "bbad1ab5f8f63fb7", + "id": "106874534890f229", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -6073,67 +4626,67 @@ "topic": "", "name": "", "x": 1090, - "y": 1520, + "y": 1540, "wires": [ [] ] }, { - "id": "a7fd00943edc380b", + "id": "5daca3ec47f8e7fc", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n msg['limit_filesize'] = float(int(load_int('osc_limit_filesize')/10000000))/100\n msg['limit_photos'] = load_int('osc_limit_photos')\n return msg\nexcept:\n pass", "outputs": 1, "x": 230, - "y": 1380, + "y": 1400, "wires": [ [ - "f7bf47e3eec6d736", - "b52d91c628b151a4", - "1969c709ef2fd1d5" + "c9f0566601a3e130", + "9bd86d27ea499a2a", + "2c37f7030810d234" ] ] }, { - "id": "124459147143ec6a", + "id": "f34de19d4cf810a9", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Motor", "info": "", "x": 90, - "y": 1600, + "y": 1740, "wires": [] }, { - "id": "dbd62b91a6c9c412", + "id": "26c2b58e21f97475", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Camera", "info": "", "x": 90, - "y": 2240, + "y": 2500, "wires": [] }, { - "id": "842b6fe016087ce3", + "id": "a8ec972bad47a9a8", "type": "comment", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Pinout", "info": "", - "x": 110, - "y": 2860, + "x": 90, + "y": 2960, "wires": [] }, { - "id": "8c1a92f2dcc976c7", + "id": "b03e8b51187e88eb", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "Rotor_delay (ms)", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 14, + "group": "7a3279eea439bcdd", + "order": 16, "width": 3, "height": 1, "passthru": false, @@ -6145,22 +4698,22 @@ "step": "0.005", "className": "", "x": 450, - "y": 1840, + "y": 2140, "wires": [ [ - "bb54bbdae6690576" + "11fd3363416433f9" ] ] }, { - "id": "2647111c06f2055d", + "id": "6aae9d4fddf08cc0", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt delay", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 27, + "group": "7a3279eea439bcdd", + "order": 30, "width": 3, "height": 1, "passthru": false, @@ -6172,22 +4725,22 @@ "step": "0.005", "className": "", "x": 420, - "y": 2080, + "y": 2380, "wires": [ [ - "fb8145a9f8d4f7b2" + "e50492d1e18f43c6" ] ] }, { - "id": "f9b51424edb0491c", + "id": "543e1690693acbeb", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_acc", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 16, + "group": "7a3279eea439bcdd", + "order": 18, "width": 3, "height": 1, "passthru": false, @@ -6199,22 +4752,22 @@ "step": "0.1", "className": "", "x": 420, - "y": 1880, + "y": 2180, "wires": [ [ - "ea87ecfd2af3cc7f" + "e8b24efb0f30288e" ] ] }, { - "id": "1ab34b0a78b2c577", + "id": "9a56c087d941f1da", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_accramp", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 18, + "group": "7a3279eea439bcdd", + "order": 20, "width": 3, "height": 1, "passthru": false, @@ -6226,22 +4779,22 @@ "step": "100", "className": "", "x": 440, - "y": 1920, + "y": 2220, "wires": [ [ - "249f44c3a87793ba" + "29f576be9e292232" ] ] }, { - "id": "1d4230b3d9b93f63", + "id": "dfdebe10dbf0e198", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_stepsperrotation", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 12, + "group": "7a3279eea439bcdd", + "order": 14, "width": 3, "height": 1, "passthru": false, @@ -6252,19 +4805,19 @@ "className": "", "topicType": "msg", "x": 460, - "y": 1800, + "y": 2100, "wires": [ [ - "0bb56b1edb12c2cf" + "78e256083f59f66f" ] ] }, { - "id": "2e3222f0aba88040", + "id": "af8dfe78cbd0c301", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 17, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 19, "width": 3, "height": 1, "name": "rotor Accramp", @@ -6273,15 +4826,15 @@ "layout": "row-left", "className": "", "x": 780, - "y": 1880, + "y": 2180, "wires": [] }, { - "id": "9d50311679acf215", + "id": "ee4b8908a5b83880", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 11, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 13, "width": 3, "height": 1, "name": "rotor_Steps per Rotation", @@ -6290,15 +4843,15 @@ "layout": "row-spread", "className": "", "x": 810, - "y": 1920, + "y": 2220, "wires": [] }, { - "id": "25d7b4dd2aab8f05", + "id": "c4deaa38c1b0adbf", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 15, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 17, "width": 3, "height": 1, "name": "rotor Acc", @@ -6307,15 +4860,15 @@ "layout": "row-left", "className": "", "x": 760, - "y": 1840, + "y": 2140, "wires": [] }, { - "id": "15682cca9622831f", + "id": "baec873a95fff48a", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 13, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 15, "width": 3, "height": 1, "name": "rotor_delay", @@ -6324,15 +4877,15 @@ "layout": "row-left", "className": "", "x": 770, - "y": 1800, + "y": 2100, "wires": [] }, { - "id": "8e2d22042bfcb4e8", + "id": "355e89ab4e5484e4", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 23, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 26, "width": 6, "height": 1, "name": "tt", @@ -6341,18 +4894,18 @@ "layout": "row-center", "className": "", "x": 90, - "y": 2040, + "y": 2300, "wires": [] }, { - "id": "56bc3b93af2ebe16", + "id": "10687d331a732790", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_acc", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 29, + "group": "7a3279eea439bcdd", + "order": 32, "width": 3, "height": 1, "passthru": false, @@ -6364,22 +4917,22 @@ "step": "0.1", "className": "", "x": 410, - "y": 2120, + "y": 2420, "wires": [ [ - "35422077b53da9bf" + "af88b9da72917d62" ] ] }, { - "id": "6ef996f8a36f94c2", + "id": "721b9680a3fa460e", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_accramp", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 31, + "group": "7a3279eea439bcdd", + "order": 34, "width": 3, "height": 1, "passthru": false, @@ -6391,22 +4944,22 @@ "step": "1", "className": "", "x": 430, - "y": 2160, + "y": 2460, "wires": [ [ - "2c000bd53cdb98ca" + "b1b4678827d3a6dd" ] ] }, { - "id": "0c50fdbb5ac3c373", + "id": "c6642c7470d3820c", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_stepsperrotation", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 25, + "group": "7a3279eea439bcdd", + "order": 28, "width": 3, "height": 1, "passthru": false, @@ -6417,19 +4970,19 @@ "className": "", "topicType": "msg", "x": 450, - "y": 2040, + "y": 2340, "wires": [ [ - "485a4bed5a6bea23" + "eef89545ec0f6aa8" ] ] }, { - "id": "213ccfb441a42890", + "id": "18e5918748660109", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 30, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 33, "width": 3, "height": 1, "name": "ttAccramp", @@ -6438,15 +4991,15 @@ "layout": "row-left", "className": "", "x": 760, - "y": 2160, + "y": 2460, "wires": [] }, { - "id": "73c9b4d09dc25e54", + "id": "8e805244dc1899e8", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 24, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 27, "width": 3, "height": 1, "name": "tt_steps per Rotation", @@ -6455,15 +5008,15 @@ "layout": "row-spread", "className": "", "x": 800, - "y": 2040, + "y": 2340, "wires": [] }, { - "id": "a81824c92f22487d", + "id": "a09e5fbea861bfb1", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 28, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 31, "width": 3, "height": 1, "name": "tt Acc", @@ -6472,15 +5025,15 @@ "layout": "row-left", "className": "", "x": 750, - "y": 2120, + "y": 2420, "wires": [] }, { - "id": "9715161858f69649", + "id": "7b06448b3b222011", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 26, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 29, "width": 3, "height": 1, "name": "tt_delay", @@ -6489,18 +5042,18 @@ "layout": "row-left", "className": "", "x": 760, - "y": 2080, + "y": 2380, "wires": [] }, { - "id": "1b3ac50d2c6600c6", + "id": "0dfc86d90258f9bb", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_angle", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 20, + "group": "7a3279eea439bcdd", + "order": 22, "width": 3, "height": 1, "passthru": false, @@ -6512,19 +5065,19 @@ "step": "1", "className": "", "x": 430, - "y": 1960, + "y": 2260, "wires": [ [ - "e0d7c36daa42b3f3" + "c4b5a38c5c1df3d2" ] ] }, { - "id": "6dcd1f0ccb01a299", + "id": "9319d7d4f34c6d22", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 19, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 21, "width": 3, "height": 1, "name": "rotor_angle", @@ -6533,18 +5086,18 @@ "layout": "row-spread", "className": "", "x": 770, - "y": 1960, + "y": 2260, "wires": [] }, { - "id": "16e9a3a71c4bb916", + "id": "1610895f430b9aca", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_angle", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 33, + "group": "7a3279eea439bcdd", + "order": 36, "width": 3, "height": 1, "passthru": false, @@ -6556,19 +5109,19 @@ "step": "1", "className": "", "x": 420, - "y": 2200, + "y": 2500, "wires": [ [ - "c34111aaec734dd9" + "0f3367983bb8e159" ] ] }, { - "id": "888161059eb9c71c", + "id": "96a9febc0928b6f0", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 32, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 35, "width": 3, "height": 1, "name": "tt_angle", @@ -6577,15 +5130,15 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2200, + "y": 2500, "wires": [] }, { - "id": "f4fc72297074c7ae", + "id": "e2c5ea8c16a5ea32", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 4, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 2, "width": 6, "height": 1, "name": "rotor", @@ -6594,18 +5147,18 @@ "layout": "row-center", "className": "", "x": 90, - "y": 1680, + "y": 1820, "wires": [] }, { - "id": "9b1d8f9e21b34102", + "id": "277037c4716d85bf", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "tt_dir", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 35, + "group": "7a3279eea439bcdd", + "order": 38, "width": 3, "height": 1, "passthru": false, @@ -6617,22 +5170,22 @@ "step": "1", "className": "", "x": 410, - "y": 2240, + "y": 2540, "wires": [ [ - "89dbbe7d99ddbbaf" + "c9d2e31514def4fc" ] ] }, { - "id": "b2e839fe47a32b5f", + "id": "1361134e9847f003", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotor_dir", "label": "", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 22, + "group": "7a3279eea439bcdd", + "order": 24, "width": 3, "height": 1, "passthru": false, @@ -6644,19 +5197,19 @@ "step": "1", "className": "", "x": 420, - "y": 2000, + "y": 2300, "wires": [ [ - "204b0a5c8629d78a" + "523717b0f218a5fd" ] ] }, { - "id": "4519daf0b4b28aef", + "id": "6b0d58943ecb8bb2", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 34, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 37, "width": 3, "height": 1, "name": "tt_dir", @@ -6665,15 +5218,15 @@ "layout": "row-spread", "className": "", "x": 750, - "y": 2240, + "y": 2540, "wires": [] }, { - "id": "5f269ea2c8a53f6c", + "id": "08f93dd2aeedb391", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 21, + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 23, "width": 3, "height": 1, "name": "rotor_dir", @@ -6682,74 +5235,47 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2000, + "y": 2300, "wires": [] }, { - "id": "b67dfacfc9a23aa5", + "id": "46b91bef44714366", "type": "link in", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "advanced settings", "links": [ - "62cd775a1c02dac8" + "8750ad979e9ea246" ], "x": 95, - "y": 80, + "y": 100, "wires": [ [ - "9b756a1f9b0e7317" + "89eedf29b404f750" ] ] }, { - "id": "62cd775a1c02dac8", + "id": "8750ad979e9ea246", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "", "mode": "link", "links": [ - "b67dfacfc9a23aa5" + "46b91bef44714366" ], "x": 955, - "y": 660, + "y": 480, "wires": [] }, { - "id": "9d94dbc523d989a3", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_delay_after", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 16, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0", - "max": "5", - "step": "0.1", - "className": "", - "x": 450, - "y": 2460, - "wires": [ - [ - "b81e238ccd0a04fe" - ] - ] - }, - { - "id": "0558d6eb9a01862e", + "id": "2522f888dc58972f", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_delay_before", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 14, + "group": "d324f0b852c2df0a", + "order": 7, "width": 3, "height": 1, "passthru": false, @@ -6757,53 +5283,26 @@ "topic": "", "topicType": "str", "min": "0", - "max": "5", - "step": "0.1", - "className": "", - "x": 440, - "y": 2500, - "wires": [ - [ - "a0048747e7300bdc" - ] - ] - }, - { - "id": "d47515c9b208bfb7", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_timeout", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 12, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0.01", "max": "1", - "step": "0.01", + "step": "0.02", "className": "", - "x": 420, - "y": 2420, + "x": 430, + "y": 2680, "wires": [ [ - "9b0d5c521a7822cc" + "5c752757090c49d2" ] ] }, { - "id": "89c76766c7552b57", + "id": "30e8df3d616512d8", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_gain", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 22, + "group": "d324f0b852c2df0a", + "order": 11, "width": 3, "height": 1, "passthru": false, @@ -6814,77 +5313,23 @@ "max": "10", "step": "0.1", "className": "", - "x": 410, - "y": 2540, - "wires": [ - [ - "9b26ed02296d27c9" - ] - ] - }, - { - "id": "c385518eb65a1b27", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_awbg_red", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 18, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-10", - "max": "10", - "step": "0.1", - "className": "", - "x": 430, - "y": 2580, - "wires": [ - [ - "b0ac7e9a7c713b84" - ] - ] - }, - { - "id": "5c80833b718d9bf6", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "cam_awbg_blue", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 20, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-10", - "max": "10", - "step": "0.1", - "className": "", - "x": 430, - "y": 2620, + "x": 400, + "y": 2720, "wires": [ [ - "827b1a671a77037d" + "a1769f0277834f6d" ] ] }, { - "id": "5a3826e112fb24e6", + "id": "d855d926df89d65b", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_contrast", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 24, + "group": "d324f0b852c2df0a", + "order": 13, "width": 3, "height": 1, "passthru": false, @@ -6895,23 +5340,24 @@ "max": "5", "step": "0.1", "className": "", - "x": 430, - "y": 2660, + "x": 420, + "y": 2840, "wires": [ [ - "78a1536c167da741" + "1a8b0ba21b4f3005", + "654bc70a18820828" ] ] }, { - "id": "3182ed7ac02b1509", + "id": "7617517dc8ba2859", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_saturation", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 26, + "group": "d324f0b852c2df0a", + "order": 15, "width": 3, "height": 1, "passthru": false, @@ -6922,22 +5368,23 @@ "max": "5", "step": "0.1", "className": "", - "x": 430, - "y": 2700, + "x": 420, + "y": 2880, "wires": [ [ - "fe9a5b68fc8c2077" + "dc8fc962ff7d594b", + "e64feb03a791ca33" ] ] }, { - "id": "7fa6337cdf0a0bc8", + "id": "cbaa23c34e10fae1", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_jpeg_q", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", + "group": "d324f0b852c2df0a", "order": 3, "width": 3, "height": 1, @@ -6949,54 +5396,20 @@ "max": "100", "step": "1", "className": "", - "x": 420, - "y": 2740, + "x": 410, + "y": 2920, "wires": [ [ - "e27d2613e942f344" + "00e7836ccb3c4d0c" ] ] }, { - "id": "08275bf96f87b8ef", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 11, - "width": 3, - "height": 1, - "name": "timeout", - "label": "Timeout", - "format": "", - "layout": "row-spread", - "className": "", - "x": 760, - "y": 2420, - "wires": [] - }, - { - "id": "d2d028df4a139f41", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 15, - "width": 3, - "height": 1, - "name": "delay_after", - "label": "Delay after", - "format": "", - "layout": "row-spread", - "className": "", - "x": 770, - "y": 2460, - "wires": [] - }, - { - "id": "c6a65762aa4ffb7b", + "id": "bbe443b039a14e21", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 13, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 6, "width": 3, "height": 1, "name": "delay_before", @@ -7004,16 +5417,16 @@ "format": "", "layout": "row-spread", "className": "", - "x": 770, - "y": 2500, + "x": 760, + "y": 2680, "wires": [] }, { - "id": "780323fd4504b855", + "id": "d320ed3d701e6cc2", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 21, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 10, "width": 3, "height": 1, "name": "gain", @@ -7021,50 +5434,16 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2540, - "wires": [] - }, - { - "id": "780bf08b41202135", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 17, - "width": 3, - "height": 1, - "name": "awbg red", - "label": "AWBG red", - "format": "", - "layout": "row-spread", - "className": "", - "x": 760, - "y": 2580, - "wires": [] - }, - { - "id": "c0faf441fc918538", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 19, - "width": 3, - "height": 1, - "name": "awbg blue", - "label": "AWBG blue", - "format": "", - "layout": "row-spread", - "className": "", - "x": 770, - "y": 2620, + "x": 740, + "y": 2720, "wires": [] }, { - "id": "93d12b447a39c5bb", + "id": "f5834dd4646c8af9", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 23, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 12, "width": 3, "height": 1, "name": "contrast", @@ -7072,16 +5451,16 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 2660, + "x": 750, + "y": 2840, "wires": [] }, { - "id": "e77e6dcd285d3062", + "id": "ae9a4e19469813ef", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 25, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 14, "width": 3, "height": 1, "name": "saturation", @@ -7089,15 +5468,15 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 2700, + "x": 750, + "y": 2880, "wires": [] }, { - "id": "a7075bc8d5ee1138", + "id": "bd629d0d31233c8b", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", "order": 2, "width": 3, "height": 1, @@ -7106,18 +5485,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2740, + "x": 740, + "y": 2920, "wires": [] }, { - "id": "282681e7c4351f74", + "id": "e89f61dbe6a6cffe", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "ext", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 3, "width": 2, "height": 1, @@ -7128,19 +5507,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 2900, + "x": 390, + "y": 3080, "wires": [ [ - "b17e82651407d8e0" + "885bc559fafec5f2" ] ] }, { - "id": "da43c58979737fec", + "id": "ece38cb172a12d75", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 2, "width": 4, "height": 1, @@ -7149,18 +5528,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2900, + "x": 730, + "y": 3080, "wires": [] }, { - "id": "ef70d61678fe1f11", + "id": "70014da0b6ab6698", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "light1", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 5, "width": 2, "height": 1, @@ -7171,19 +5550,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 2940, + "x": 390, + "y": 3120, "wires": [ [ - "2c812acffdb330c5" + "f70321c96bf81360" ] ] }, { - "id": "fec56a7e913b21d6", + "id": "29634ea5f6d666df", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 4, "width": 4, "height": 1, @@ -7192,18 +5571,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2940, + "x": 730, + "y": 3120, "wires": [] }, { - "id": "24929b4629f22070", + "id": "2544963852c6881a", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "light2", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 7, "width": 2, "height": 1, @@ -7214,19 +5593,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 2980, + "x": 390, + "y": 3160, "wires": [ [ - "ae0654af69446942" + "95e1603bbd06a69d" ] ] }, { - "id": "7c6bdc0504aa4cc7", + "id": "27903533cd85a59e", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 6, "width": 4, "height": 1, @@ -7235,18 +5614,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 2980, + "x": 730, + "y": 3160, "wires": [] }, { - "id": "8c396b060f3d2646", + "id": "a1394401246eb735", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotordir", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 9, "width": 2, "height": 1, @@ -7257,19 +5636,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3020, + "x": 400, + "y": 3200, "wires": [ [ - "58cf48cfacc979fb" + "a8f92ea6bf394640" ] ] }, { - "id": "97568610daccf74a", + "id": "bc0aa4bacdfa94ea", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 8, "width": 4, "height": 1, @@ -7278,18 +5657,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3020, + "x": 740, + "y": 3200, "wires": [] }, { - "id": "a3c58ea48c388215", + "id": "f15ca4518b5f223e", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotorstep", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 11, "width": 2, "height": 1, @@ -7300,19 +5679,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3060, + "x": 400, + "y": 3240, "wires": [ [ - "c7ae206f2fff6810" + "06397bb46b3bb541" ] ] }, { - "id": "6da92aeaeffd95e0", + "id": "0d2924b160e7e383", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 10, "width": 4, "height": 1, @@ -7321,18 +5700,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3060, + "x": 740, + "y": 3240, "wires": [] }, { - "id": "9b5da90eaf6ac562", + "id": "49900bb9047dd965", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "rotoren", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 13, "width": 2, "height": 1, @@ -7343,19 +5722,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3100, + "x": 400, + "y": 3280, "wires": [ [ - "cfebd4a47a68b319" + "687dcdc1ede11700" ] ] }, { - "id": "12623e4addfa2c22", + "id": "a4d743ca73ee1622", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 12, "width": 4, "height": 1, @@ -7364,18 +5743,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3100, + "x": 740, + "y": 3280, "wires": [] }, { - "id": "f24cb404d7d09f8a", + "id": "5a90224dc998b417", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "ttdir", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 15, "width": 2, "height": 1, @@ -7386,19 +5765,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 3140, + "x": 390, + "y": 3320, "wires": [ [ - "90f4d220928e4727" + "e220740c0d38ccb0" ] ] }, { - "id": "542bfb9d92935c2c", + "id": "67dc1b544c4ddf9f", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 14, "width": 4, "height": 1, @@ -7407,18 +5786,18 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 3140, + "x": 730, + "y": 3320, "wires": [] }, { - "id": "1f79467df98ce894", + "id": "d2364ab09627fe94", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "ttstep", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", + "group": "70d0be671bf03ca7", "order": 17, "width": 2, "height": 1, @@ -7429,19 +5808,19 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 410, - "y": 3180, + "x": 390, + "y": 3360, "wires": [ [ - "b05e1e612887f9c2" + "79d7e5a705ab813a" ] ] }, { - "id": "170d3b925f7745cc", + "id": "145b67ac40721ba6", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", "order": 16, "width": 4, "height": 1, @@ -7450,19 +5829,19 @@ "format": "", "layout": "row-spread", "className": "", - "x": 750, - "y": 3180, + "x": 730, + "y": 3360, "wires": [] }, { - "id": "661614f5bd2c71d6", + "id": "eef25405472acfee", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "endstop1", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", - "order": 21, + "group": "70d0be671bf03ca7", + "order": 19, "width": 2, "height": 1, "passthru": false, @@ -7472,20 +5851,20 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3220, + "x": 400, + "y": 3400, "wires": [ [ - "2af447a6905b83bc" + "12d20f2274bcc511" ] ] }, { - "id": "c18b55859dae5f85", + "id": "35eb252a41413531", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", - "order": 20, + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 18, "width": 4, "height": 1, "name": "endstop1", @@ -7493,19 +5872,19 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3220, + "x": 740, + "y": 3400, "wires": [] }, { - "id": "e23a396162026618", + "id": "74e455136b5ca5dd", "type": "ui_text_input", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "endstop2", "label": "", "tooltip": "", - "group": "644b3bcc903d46ca", - "order": 23, + "group": "70d0be671bf03ca7", + "order": 21, "width": 2, "height": 1, "passthru": false, @@ -7515,20 +5894,20 @@ "sendOnBlur": true, "className": "", "topicType": "msg", - "x": 420, - "y": 3260, + "x": 400, + "y": 3440, "wires": [ [ - "787a128f84f747c0" + "a4a89668ce4c9f05" ] ] }, { - "id": "82c1a33014d003e9", + "id": "3a74f653800eb831", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "644b3bcc903d46ca", - "order": 22, + "z": "e43a27722b508115", + "group": "70d0be671bf03ca7", + "order": 20, "width": 4, "height": 1, "name": "endstop2", @@ -7536,14 +5915,14 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 3260, + "x": 740, + "y": 3440, "wires": [] }, { - "id": "5255759a7c5b2a74", + "id": "5fcef1cb2e9e4788", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", @@ -7556,37 +5935,37 @@ "topic": "", "name": "confirm", "x": 680, - "y": 660, + "y": 480, "wires": [ [ - "15fd1c9e5610cb85" + "29745a36fc157f3f" ] ] }, { - "id": "8be8015931c663cc", + "id": "f06a7bcad524e9f9", "type": "python3-function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", "outputs": 1, "x": 530, - "y": 660, + "y": 480, "wires": [ [ - "5255759a7c5b2a74" + "5fcef1cb2e9e4788" ] ] }, { - "id": "9d464b2ba1edaf48", + "id": "f455fb39039617ae", "type": "ui_slider", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "cam_rotation", "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 10, + "group": "d324f0b852c2df0a", + "order": 5, "width": 3, "height": 1, "passthru": false, @@ -7597,20 +5976,20 @@ "max": "270", "step": "90", "className": "", - "x": 420, - "y": 2780, + "x": 410, + "y": 2960, "wires": [ [ - "b7d3fe0c0b40b3e1" + "3019576de193d9d6" ] ] }, { - "id": "db98b95693ebce63", + "id": "fdfbc900fe424eb9", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 9, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 4, "width": 3, "height": 1, "name": "cam_rot", @@ -7618,14 +5997,14 @@ "format": "", "layout": "row-spread", "className": "", - "x": 760, - "y": 2780, + "x": 750, + "y": 2960, "wires": [] }, { - "id": "6659121906897a1f", + "id": "c3699d6b9664ccca", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7634,17 +6013,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1800, + "y": 2100, "wires": [ [ - "1d4230b3d9b93f63" + "dfdebe10dbf0e198" ] ] }, { - "id": "0bb56b1edb12c2cf", + "id": "78e256083f59f66f", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7653,15 +6032,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1800, + "y": 2100, "wires": [ [] ] }, { - "id": "569829eeff715c33", + "id": "0f9141b401322374", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7670,17 +6049,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1920, + "y": 2220, "wires": [ [ - "1ab34b0a78b2c577" + "9a56c087d941f1da" ] ] }, { - "id": "249f44c3a87793ba", + "id": "29f576be9e292232", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7689,15 +6068,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1920, + "y": 2220, "wires": [ [] ] }, { - "id": "c997e60519341afd", + "id": "23e3099b34c4e475", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7706,17 +6085,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1960, + "y": 2260, "wires": [ [ - "1b3ac50d2c6600c6" + "0dfc86d90258f9bb" ] ] }, { - "id": "e0d7c36daa42b3f3", + "id": "c4b5a38c5c1df3d2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7725,15 +6104,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1960, + "y": 2260, "wires": [ [] ] }, { - "id": "59ecf3a22cd3a669", + "id": "79a14162ac805fac", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7742,17 +6121,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2000, + "y": 2300, "wires": [ [ - "b2e839fe47a32b5f" + "1361134e9847f003" ] ] }, { - "id": "204b0a5c8629d78a", + "id": "523717b0f218a5fd", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7761,15 +6140,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2000, + "y": 2300, "wires": [ [] ] }, { - "id": "15f02421b30a9ab6", + "id": "f5cf780f3fa8997e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", "outputs": 1, @@ -7778,17 +6157,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1840, + "y": 2140, "wires": [ [ - "8c1a92f2dcc976c7" + "b03e8b51187e88eb" ] ] }, { - "id": "bb54bbdae6690576", + "id": "11fd3363416433f9", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7797,15 +6176,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 1840, + "y": 2140, "wires": [ [] ] }, { - "id": "58928befcc61b1f7", + "id": "02060b3f3b294563", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, @@ -7814,17 +6193,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 1880, + "y": 2180, "wires": [ [ - "f9b51424edb0491c" + "543e1690693acbeb" ] ] }, { - "id": "ea87ecfd2af3cc7f", + "id": "e8b24efb0f30288e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'rotor_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7833,34 +6212,34 @@ "finalize": "", "libs": [], "x": 630, - "y": 1880, + "y": 2180, "wires": [ [] ] }, { - "id": "27bc56f273360ac7", + "id": "de1ad8b27b72a5ac", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nsteps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", "outputs": 1, - "noerr": 0, + "noerr": 4, "initialize": "", "finalize": "", "libs": [], "x": 290, - "y": 2040, + "y": 2340, "wires": [ [ - "0c50fdbb5ac3c373" + "c6642c7470d3820c" ] ] }, { - "id": "f46ced86106306c8", + "id": "ed4d587cb4feb064", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7869,17 +6248,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2160, + "y": 2460, "wires": [ [ - "6ef996f8a36f94c2" + "721b9680a3fa460e" ] ] }, { - "id": "4339704cd8552eb3", + "id": "5b02160c33605ae7", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7888,17 +6267,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2200, + "y": 2500, "wires": [ [ - "16e9a3a71c4bb916" + "1610895f430b9aca" ] ] }, { - "id": "1ac53bb6150645fe", + "id": "304c135ec09801e3", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, @@ -7907,17 +6286,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2240, + "y": 2540, "wires": [ [ - "9b1d8f9e21b34102" + "277037c4716d85bf" ] ] }, { - "id": "9b89eb1eaf333c10", + "id": "a91dcbe0f9a2416a", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) * 1000;\nreturn msg", "outputs": 1, @@ -7926,17 +6305,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2080, + "y": 2380, "wires": [ [ - "2647111c06f2055d" + "6aae9d4fddf08cc0" ] ] }, { - "id": "2e8927be0e235fa1", + "id": "6b2eb1cb95e573f9", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, @@ -7945,17 +6324,17 @@ "finalize": "", "libs": [], "x": 290, - "y": 2120, + "y": 2420, "wires": [ [ - "56bc3b93af2ebe16" + "10687d331a732790" ] ] }, { - "id": "485a4bed5a6bea23", + "id": "eef89545ec0f6aa8", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7964,15 +6343,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2040, + "y": 2340, "wires": [ [] ] }, { - "id": "2c000bd53cdb98ca", + "id": "b1b4678827d3a6dd", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_accramp'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7981,15 +6360,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2160, + "y": 2460, "wires": [ [] ] }, { - "id": "c34111aaec734dd9", + "id": "0f3367983bb8e159", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -7998,15 +6377,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2200, + "y": 2500, "wires": [ [] ] }, { - "id": "89dbbe7d99ddbbaf", + "id": "c9d2e31514def4fc", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nif (msg.payload === 1){\n content = '1'\n}\nelse{\n content = '-1'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -8015,15 +6394,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2240, + "y": 2540, "wires": [ [] ] }, { - "id": "fb8145a9f8d4f7b2", + "id": "e50492d1e18f43c6", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_delay'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload / 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -8032,15 +6411,15 @@ "finalize": "", "libs": [], "x": 630, - "y": 2080, + "y": 2380, "wires": [ [] ] }, { - "id": "35422077b53da9bf", + "id": "af88b9da72917d62", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", "func": "var file = 'tt_acc'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -8049,1083 +6428,1172 @@ "finalize": "", "libs": [], "x": 630, - "y": 2120, + "y": 2420, "wires": [ [] ] }, { - "id": "d5308090f2b7971a", + "id": "43fe948b3e7234e2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", - "func": "var file = 'cam_timeout'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2420, + "x": 280, + "y": 2680, "wires": [ [ - "d47515c9b208bfb7" + "2522f888dc58972f" ] ] }, { - "id": "9b0d5c521a7822cc", + "id": "5c752757090c49d2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_timeout'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2420, + "x": 620, + "y": 2680, "wires": [ [] ] }, { - "id": "694d1068bea15171", + "id": "435681b3f7625a7e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", - "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2460, + "x": 280, + "y": 2720, "wires": [ [ - "9d94dbc523d989a3" + "30e8df3d616512d8" ] ] }, { - "id": "cec3e5e78a40476b", + "id": "a1769f0277834f6d", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2500, + "x": 620, + "y": 2720, "wires": [ - [ - "0558d6eb9a01862e" - ] + [] ] }, { - "id": "b81e238ccd0a04fe", + "id": "1de07c7d285cbaf3", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2460, + "x": 280, + "y": 2840, "wires": [ - [] + [ + "d855d926df89d65b" + ] ] }, { - "id": "a0048747e7300bdc", + "id": "1a8b0ba21b4f3005", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_delay_before'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2500, + "x": 620, + "y": 2840, "wires": [ [] ] }, { - "id": "6f524f9370a18482", + "id": "ebc9e283468eda31", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadF", - "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2540, + "x": 280, + "y": 2880, "wires": [ [ - "89c76766c7552b57" + "7617517dc8ba2859" ] ] }, { - "id": "9b26ed02296d27c9", + "id": "dc8fc962ff7d594b", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_gain'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2540, + "x": 620, + "y": 2880, "wires": [ [] ] }, { - "id": "1f87f473e327c3cc", + "id": "60d641613527c736", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_awbg_red'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2580, + "x": 280, + "y": 2920, "wires": [ [ - "c385518eb65a1b27" + "cbaa23c34e10fae1" ] ] }, { - "id": "b0ac7e9a7c713b84", + "id": "00e7836ccb3c4d0c", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_awbg_red'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2580, + "x": 620, + "y": 2920, "wires": [ [] ] }, { - "id": "cff7ac5f1e061855", + "id": "7f24c0c34a88ba04", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_awbg_blue'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2620, + "x": 280, + "y": 2960, "wires": [ [ - "5c80833b718d9bf6" + "f455fb39039617ae" ] ] }, { - "id": "827b1a671a77037d", + "id": "3019576de193d9d6", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_awbg_blue'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2620, + "x": 620, + "y": 2960, "wires": [ [] ] }, { - "id": "cf854461c37ca54f", + "id": "77bb7dc529d63a7e", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2660, + "x": 270, + "y": 3080, "wires": [ [ - "5a3826e112fb24e6" + "e89f61dbe6a6cffe" ] ] }, { - "id": "78a1536c167da741", + "id": "885bc559fafec5f2", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_contrast'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2660, + "x": 590, + "y": 3080, "wires": [ [] ] }, { - "id": "ba10e04dd1761692", + "id": "cc6dabe017a9c8a8", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadF", - "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2700, + "x": 270, + "y": 3400, "wires": [ [ - "3182ed7ac02b1509" + "eef25405472acfee" ] ] }, { - "id": "fe9a5b68fc8c2077", + "id": "12d20f2274bcc511", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_saturation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2700, + "x": 590, + "y": 3400, "wires": [ [] ] }, { - "id": "a69d216114f908a5", + "id": "dcb9fed8122759fd", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2740, + "x": 270, + "y": 3120, "wires": [ [ - "7fa6337cdf0a0bc8" + "70014da0b6ab6698" ] ] }, { - "id": "e27d2613e942f344", + "id": "f70321c96bf81360", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_jpeg_quality'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2740, + "x": 590, + "y": 3120, "wires": [ [] ] }, { - "id": "f02d4a036a225e87", + "id": "013d2057c2347a62", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2780, + "x": 270, + "y": 3160, "wires": [ [ - "9d464b2ba1edaf48" + "2544963852c6881a" ] ] }, { - "id": "b7d3fe0c0b40b3e1", + "id": "95e1603bbd06a69d", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_rotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2780, + "x": 590, + "y": 3160, "wires": [ [] ] }, { - "id": "612cccacda1a65aa", + "id": "f88bbf11d5aa9a14", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2900, + "x": 270, + "y": 3200, "wires": [ [ - "282681e7c4351f74" + "a1394401246eb735" ] ] }, { - "id": "b17e82651407d8e0", + "id": "a8f92ea6bf394640", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_external'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 2900, + "x": 590, + "y": 3200, "wires": [ [] ] }, { - "id": "3b126549c03a872e", + "id": "301af70731e096e5", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3220, + "x": 270, + "y": 3240, "wires": [ [ - "661614f5bd2c71d6" + "f15ca4518b5f223e" ] ] }, { - "id": "2af447a6905b83bc", + "id": "06397bb46b3bb541", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_rotor_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3220, + "x": 590, + "y": 3240, "wires": [ [] ] }, { - "id": "954db931f87894ee", + "id": "0456a9ec4c236c9e", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2940, + "x": 270, + "y": 3280, "wires": [ [ - "ef70d61678fe1f11" + "49900bb9047dd965" ] ] }, { - "id": "2c812acffdb330c5", + "id": "687dcdc1ede11700", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_ringlight1'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 2940, + "x": 590, + "y": 3280, "wires": [ [] ] }, { - "id": "6682c8057e89d087", + "id": "09d37ba08ec0f163", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2980, + "x": 270, + "y": 3320, "wires": [ [ - "24929b4629f22070" + "5a90224dc998b417" ] ] }, { - "id": "ae0654af69446942", + "id": "37d954a4cf7e87ea", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'pin_ringlight2'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 2980, + "x": 270, + "y": 3360, "wires": [ - [] + [ + "d2364ab09627fe94" + ] ] }, { - "id": "015be401d08047d2", + "id": "e220740c0d38ccb0", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3020, + "x": 590, + "y": 3320, "wires": [ - [ - "8c396b060f3d2646" - ] + [] ] }, { - "id": "58cf48cfacc979fb", + "id": "79d7e5a705ab813a", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_rotor_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3020, + "x": 590, + "y": 3360, "wires": [ [] ] }, { - "id": "1c6c0f8b9ac95659", + "id": "21dc963d967d9c99", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3060, + "x": 270, + "y": 3440, "wires": [ [ - "a3c58ea48c388215" + "74e455136b5ca5dd" ] ] }, { - "id": "c7ae206f2fff6810", + "id": "a4a89668ce4c9f05", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_rotor_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3060, + "x": 590, + "y": 3440, "wires": [ [] ] }, { - "id": "dcee66c0d56c6934", + "id": "22ef66b0e2058be2", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3100, + "x": 270, + "y": 360, "wires": [ [ - "9b5da90eaf6ac562" + "cb3437ec113e1b6f" ] ] }, { - "id": "cfebd4a47a68b319", + "id": "9ce01c8ba97932c1", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'pin_rotor_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3100, + "x": 270, + "y": 400, "wires": [ - [] + [ + "60fd0adce1cfeb82" + ] ] }, { - "id": "6ec7d85bb17eb159", + "id": "81356177176eebcf", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3140, + "x": 270, + "y": 480, "wires": [ [ - "f24cb404d7d09f8a" + "f6d6cc35679ede63" ] ] }, { - "id": "4f42d02a3776a006", + "id": "b78346ca3ce70c68", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 3180, + "x": 270, + "y": 320, "wires": [ [ - "1f79467df98ce894" + "f0d8dbcca76a1926" ] ] }, { - "id": "90f4d220928e4727", + "id": "e95b86cbac1b03b9", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_tt_dir'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var data\n\nif(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3140, + "x": 550, + "y": 320, "wires": [ [] ] }, { - "id": "b05e1e612887f9c2", + "id": "3e4c15d7b538f816", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'pin_tt_step'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "msg", + "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3180, + "x": 670, + "y": 1540, "wires": [ - [] + [ + "3bf622f344172721" + ] ] }, { - "id": "58bbe9fc41e0d7b9", + "id": "0f0871baf322b6d0", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 290, - "y": 3260, + "y": 1820, "wires": [ [ - "e23a396162026618" + "6ebd15c61a5ca891" ] ] }, { - "id": "787a128f84f747c0", + "id": "f21a95a732fadae6", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 5, + "width": 3, + "height": 1, + "name": "rotor_anglemin", + "label": "Min Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1820, + "wires": [] + }, + { + "id": "acd10a4c99ee8063", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'pin_tt_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 610, - "y": 3260, + "x": 630, + "y": 1820, "wires": [ [] ] }, { - "id": "78351089ee9ebeaf", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 340, + "id": "6ebd15c61a5ca891", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemin", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 6, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1820, "wires": [ [ - "40dee936a9abac0d" + "acd10a4c99ee8063" ] ] }, { - "id": "5fba78ae65eaaf5d", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 380, + "id": "3ad0f0f206e4a873", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglemax", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 8, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1860, "wires": [ [ - "4fd9bb53fdb51a25" + "031d7697768d0e77" ] ] }, { - "id": "67206663b3881868", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'advanced_settings'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 660, + "id": "3b6d759ed5be647f", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "rotor_anglestart", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 4, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "5", + "className": "", + "x": 440, + "y": 1900, "wires": [ [ - "c833f6243a059d83" + "be1954dd71d2c94c" ] ] }, { - "id": "3492754252645e62", + "id": "edb1c8fae8b65c82", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'camera'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 420, + "x": 290, + "y": 1860, "wires": [ [ - "a2c1dba3e67be015", - "6f3d403e157163e4" + "3ad0f0f206e4a873" ] ] }, { - "id": "d16525a31223bc42", + "id": "031d7697768d0e77", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'model'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 620, + "x": 630, + "y": 1860, "wires": [ - [ - "80b579a4220e5c23", - "c6138801b30f091d" - ] + [] ] }, { - "id": "f99ec8781a33ec7d", + "id": "462a8f3ca75fc3c8", "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By pressing GET FEATURES you agree that the shown preview image will be transfered, stored and processed via SFTP to my servers '+\n '(Thomas Megel, OpenScan, Halle, Germany). The IP address will be saved for 14 days The images might be used for further experiments (e.g. machine learning, automation ...). '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 270, - "y": 300, + "x": 290, + "y": 1900, "wires": [ [ - "7dc39bd847d16ded" + "3b6d759ed5be647f" ] ] }, { - "id": "5f849178998d9082", + "id": "be1954dd71d2c94c", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "if(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", + "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 550, - "y": 300, + "x": 630, + "y": 1900, "wires": [ [] ] }, { - "id": "725fd0cab0bddc0e", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'hostname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 250, - "y": 940, + "id": "3d7379753d2eda25", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 7, + "width": 3, + "height": 1, + "name": "rotor_anglemax", + "label": "Max Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1860, + "wires": [] + }, + { + "id": "9cc86d1bcae3ab4e", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 3, + "width": 3, + "height": 1, + "name": "rotor_anglestart", + "label": "Start Angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 1900, + "wires": [] + }, + { + "id": "2e9b29c70969cf01", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 135, + "y": 360, "wires": [ [ - "49259adad52fc214" + "22ef66b0e2058be2", + "9ce01c8ba97932c1", + "81356177176eebcf", + "d54b85891248ba88" ] ] }, { - "id": "49259adad52fc214", - "type": "ui_text_input", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Hostname", - "tooltip": "", - "group": "0fe66c9190b8a87c", - "order": 6, - "width": 6, - "height": 1, - "passthru": false, - "mode": "text", - "delay": "0", - "topic": "Change hostname to:", - "sendOnBlur": true, - "className": "", - "topicType": "str", - "x": 530, + "id": "592ec13d8f8923a9", + "type": "link in", + "z": "e43a27722b508115", + "name": "ip address", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc", + "eb1a2387a1eeea76", + "c994c779e4bad800" + ], + "x": 85, "y": 940, "wires": [ [ - "8001f7c361de7d8c" + "ded3086945a6d4b5", + "6ea3cdab41f20f92" ] ] }, { - "id": "51521bc6eb44cde5", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.enabled = false\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 250, - "y": 980, + "id": "cb40b9341bd22a28", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 185, + "y": 1820, "wires": [ [ - "59c9f67283ba1709" + "0f0871baf322b6d0", + "edb1c8fae8b65c82", + "462a8f3ca75fc3c8", + "c3699d6b9664ccca", + "f5cf780f3fa8997e", + "02060b3f3b294563", + "0f9141b401322374", + "23e3099b34c4e475", + "79a14162ac805fac", + "de1ad8b27b72a5ac", + "a91dcbe0f9a2416a", + "6b2eb1cb95e573f9", + "ed4d587cb4feb064", + "5b02160c33605ae7", + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd", + "fe62e12d458db2d4" ] ] }, { - "id": "2bb52656f9554dab", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "ssid = msg.payload\nmsg.topic = 'Add wifi network (' + ssid + ')'\nmsg.payload = 'Enter Wifi password:'\nmsg.ssid = ssid\n\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 650, - "y": 980, + "id": "d1efcd5fa9d25785", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 155, + "y": 2540, "wires": [ [ - "ebcc98685059b9d4" + "43fe948b3e7234e2", + "435681b3f7625a7e", + "1de07c7d285cbaf3", + "ebc9e283468eda31", + "60d641613527c736", + "7f24c0c34a88ba04", + "6281b2e6e081104d" ] ] }, { - "id": "ebce67b739d1891f", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "chk/change hostname", - "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n pass\n\nwith open('/etc/hostname', 'r') as file:\n old_hostname = file.read().replace('\\n','')\n\nhostname = msg['hostname']\nif len(hostname) < 4 :\n msg['payload'] = ' '\n msg['topic'] = 'ERROR - Hostname NOT changed'\n return msg\n \n\nwith open('/etc/hostname', 'w+') as file:\n file.write(hostname)\nos.system('echo ' + hostname + ' | tee /etc/hostname')\nwith open('/etc/hosts', 'r') as file:\n temp = file.read()\ntemp = temp.replace(old_hostname,hostname)\nwith open('/etc/hosts', 'w') as file:\n file.write(temp)\nos.system('hostnamectl set-hostname ' + hostname)\nos.system('systemctl restart avahi-daemon')\nsave('hostname',hostname)\nmsg['payload'] = hostname\nmsg['topic'] = 'Success - Hostname changed'\nreturn msg\n", - "outputs": 1, - "x": 1140, - "y": 940, + "id": "da61581182b7299e", + "type": "link in", + "z": "e43a27722b508115", + "name": "enable projectname", + "links": [ + "960912e90ba5b5bc", + "50eeb3e362f9027f" + ], + "x": 135, + "y": 3000, + "wires": [ + [ + "77bb7dc529d63a7e", + "dcb9fed8122759fd", + "013d2057c2347a62", + "f88bbf11d5aa9a14", + "301af70731e096e5", + "0456a9ec4c236c9e", + "09d37ba08ec0f163", + "37d954a4cf7e87ea", + "cc6dabe017a9c8a8", + "21dc963d967d9c99" + ] + ] + }, + { + "id": "7e1c84ec516ad0a6", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Reset default", + "group": "4390b2ebcbbe104c", + "order": 6, + "width": 6, + "height": 1, + "passthru": false, + "label": "Restore default settings", + "tooltip": "", + "color": "red", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "This can not be undone!", + "payloadType": "str", + "topic": "Restore default settings?", + "topicType": "str", + "x": 110, + "y": 620, "wires": [ [ - "03732a7d3b0c95aa" + "53e6681d7254d484" ] ] }, { - "id": "667ac2aba819f506", + "id": "53e6681d7254d484", "type": "ui_toast", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "position": "dialog", "displayTime": "3", "highlight": "", "sendall": true, "outputs": 1, - "ok": "OK", - "cancel": "Cancel", + "ok": "No", + "cancel": "Yes", "raw": false, "className": "", "topic": "", - "name": "Confirm", - "x": 920, - "y": 940, - "wires": [ - [ - "ebce67b739d1891f" - ] - ] - }, - { - "id": "8001f7c361de7d8c", - "type": "change", - "z": "017bd4e4a428bee5", "name": "", - "rules": [ - { - "t": "set", - "p": "hostname", - "pt": "msg", - "to": "payload", - "tot": "msg" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 710, - "y": 940, - "wires": [ - [ - "667ac2aba819f506" - ] - ] - }, - { - "id": "9bb0adbd716ce347", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "reboot", - "links": [ - "16c76929f88df841", - "fe3a855fee9e28c6" - ], - "x": 155, - "y": 720, + "x": 270, + "y": 620, "wires": [ [ - "d114f4d4d7f31981", - "cc3cb10f2ea3f8b8" + "c11e79cfa7bc10b7" ] ] }, { - "id": "f9efcb87b74abbd4", + "id": "c11e79cfa7bc10b7", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "msg", - "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", + "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 670, - "y": 1520, + "x": 410, + "y": 620, "wires": [ [ - "510dbe4d76253bd6" + "307782d10c1acdaf" ] ] }, { - "id": "adc206aa8edd1e41", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "OSC", - "group": "db43d646.2074c8", - "order": 2, - "width": 3, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", + "id": "307782d10c1acdaf", + "type": "link out", + "z": "e43a27722b508115", + "name": "", + "mode": "link", + "links": [ + "38783aea9cc317a6" + ], + "x": 505, + "y": 620, + "wires": [] + }, + { + "id": "5fff689f9f8bc1ca", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, + "outputs": 1, + "ok": "OK", + "cancel": "", + "raw": true, "className": "", - "icon": "fa-question-circle", - "payload": "

Files&Cloud

Refresh

You can refresh the status of the processing of your files in the OpenScanCloud. Make sure to read and agree the terms of use (in settings menu) before using the OpenScanCloud. Do not spam this button, as this might lead to temporary/permanent suspension of your IP address.

The status (in the table) of the individual sets in the file list will be updated to one of the following:

Created - you started the upload of your image set. If you are stuck on this status, please try to restart the upload.

Initialized - all files have been uploaded and processing will start as soon as possible

File approved - the server received and verified your files

Processing started - your files are currently being processed

Processing failed - there are various reasons why processing might fail. Please check the email for more details or contact me at cloud@openscan.eu

processing done - check your email, where you should find a link to the 3d model :)

Status (on the right column)

Indicates, what the device is currently up to.

Refreshing - updating all image set's status

Uploading - while transferring the image set to the OpenScanCloud servers. If the upload freezes, be patient. If nothing happens, reboot the device and restart the upload.

Project started - when the upload of a set was successful

Zipping - files larger then 200mb have to be split and re-zipped before uploading to the OpenScanCloud, the process might take a while depending on the filesize.

Combining - two sets into one might take up to a minute.

Set

select a set from the file list by clicking on a row in the table

Download

Download the selected set from the OpenScan device to your computer/mobile/tablet

Upload

Upload the selected file to the OpenScanCloud

Combine

In order to combine two sets, select one set. Click the combine button and select the second set. A pop-up will appear, and you can confirm the operation. All images from the two sets will be merged into one set. The original image sets will be deleted!

Delete Set/All

Please keep in mind, that the memory of the SD card is relatively small, and thus you will have to delete individual or all photo sets from time to time.

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 590, - "y": 200, + "topic": "", + "name": "Info", + "x": 1010, + "y": 140, "wires": [ - [ - "f304680180a23479" - ] + [] ] }, { - "id": "45df91cae421e8e1", + "id": "cca3300a8f0daf4d", "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Scan_settings", - "group": "7aaf184330605300", + "z": "e43a27722b508115", + "name": "Update&Info", + "group": "ddbd496e.93a288", "order": 1, "width": 6, "height": 1, @@ -9136,917 +7604,1071 @@ "bgcolor": "transparent", "className": "", "icon": "fa-question-circle", - "payload": "

Scan Settings

Current Status

--READY-- - everything is okay and ready to go :)

Routine-preparing - before starting the routine some time might pass depending on the number of photos

Routine-stopping - manually ending the routine by pressing the stop button

Routine-Photo X/Y - Showing the progress of the routine

No Camera Found - please check the camera ribbon cable

Error: XXX - Please contact info@openscan.eu or post an issue on Github.com

Projectname

Each photo set will be saved using the following pattern  YYYY-MM-DD_hh-mm-ss_projectname.zip (e.g. 2022-04-05_12.12.12_toysoldier.zip). Keep your files organized by giving each set a new projectname. If not specified 'default' will be used.

Rotor

Moving the rotor by increments of 5°. Please make sure to start the routine with the camera in the horizontal position.

Turntable

Moving the turntable by increments of 15°.

Ringlight

Use the ring light for shadow-free illumination. It is highly recommended to use the polarizer in order to avoid reflections. Note, that the polarizer will absorb 75% of the light, so you might need to use both ring lights.

Photos

Set the number of photos for the current set. 60-120 photos should be more than enough for most objects. If the reconstruction fails or is very bad with 60 photos, increasing the number of photos will not help!

Shutter

Again: Less is more! If the value is too high, some areas might get overexposed and thus, the software will not be able to recognize the surface feature of the object. Here are some reference values:

- no polarizer: 5-20ms

- mostly white object,  with polarizer + one ringlight: 50-200ms

Crop X/Y

Make sure to use the right object holder to place the object in the middle of the screen. Try to crop as many unnecessary areas as possible. This will greatly lower the file size and resulting transfer and reconstruction times!

Start/Stop

Use the buttons to start/stop the routine

Reboot/Shutdown

In case of an error, try to restart the device. Always use the shutdown button before powering-off the device!

", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 760, - "y": 120, + "x": 750, + "y": 180, "wires": [ [ - "f304680180a23479" + "5fff689f9f8bc1ca" ] ] }, { - "id": "e9677b85856b5873", + "id": "654bc70a18820828", "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "Reset rfkill", - "func": "from os import system\nif \"Interface doesn't support scanning\" in msg['payload']:\n system('rfkill unblock all')\n system('ifconfig wlan0 up')\n return msg", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/picam2_contrast?contrast=\" + str(msg['payload']))", "outputs": 1, - "x": 390, - "y": 1100, + "x": 660, + "y": 2800, "wires": [ [] ] }, { - "id": "91fe20cb16f54293", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "id": "e64feb03a791ca33", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import camera\n\ncamera(\"/picam2_saturation?saturation=\" + str(msg['payload']))", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 1680, + "x": 660, + "y": 2760, + "wires": [ + [] + ] + }, + { + "id": "81bd4381cd029958", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "cam_delay_after", + "label": "", + "tooltip": "", + "group": "d324f0b852c2df0a", + "order": 9, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "0", + "max": "1", + "step": "0.02", + "className": "", + "x": 440, + "y": 2640, "wires": [ [ - "327c8bdde31033a4" + "e612073aded01a8f" ] ] }, { - "id": "add3e998b097c54f", + "id": "0d92559980944ae3", "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 7, + "z": "e43a27722b508115", + "group": "d324f0b852c2df0a", + "order": 8, "width": 3, "height": 1, - "name": "rotor_anglemin", - "label": "Min Angle", + "name": "delay_after", + "label": "Delay after", "format": "", - "layout": "row-left", + "layout": "row-spread", "className": "", - "x": 780, - "y": 1680, + "x": 760, + "y": 2640, "wires": [] }, { - "id": "da286366433c83a0", + "id": "6281b2e6e081104d", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", + "name": "loadF", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 280, + "y": 2640, + "wires": [ + [ + "81bd4381cd029958" + ] + ] + }, + { + "id": "e612073aded01a8f", + "type": "function", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'rotor_anglemin'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "func": "var file = 'cam_delay_after'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 1680, + "x": 620, + "y": 2640, "wires": [ [] ] }, { - "id": "327c8bdde31033a4", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "rotor_anglemin", - "label": "", + "id": "e2411b49791840e0", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "reboot", + "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('reboot -h')\n", + "outputs": 1, + "x": 270, + "y": 520, + "wires": [ + [] + ] + }, + { + "id": "01c882fcc51b349c", + "type": "link in", + "z": "e43a27722b508115", + "name": "reboot", + "links": [ + "16c76929f88df841", + "fe3a855fee9e28c6", + "09d4a9c756161e10" + ], + "x": 155, + "y": 520, + "wires": [ + [ + "e2411b49791840e0" + ] + ] + }, + { + "id": "e51dd5e5c0f050d6", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "SSID", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 8, - "width": 3, + "group": "8ab79a98e536e0d6", + "order": 4, + "width": 6, "height": 1, "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-90", - "max": "90", - "step": "5", + "mode": "text", + "delay": "0", + "topic": "ssid", + "sendOnBlur": true, "className": "", - "x": 440, - "y": 1680, + "topicType": "str", + "x": 210, + "y": 980, "wires": [ [ - "da286366433c83a0" + "a7d233f984009e2e" ] ] }, { - "id": "94288df4c6756197", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "rotor_anglemax", - "label": "", + "id": "9959649037cb063b", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Password", "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 10, - "width": 3, + "group": "8ab79a98e536e0d6", + "order": 5, + "width": 6, "height": 1, "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "-90", - "max": "90", - "step": "5", + "mode": "password", + "delay": "0", + "topic": "password", + "sendOnBlur": true, "className": "", - "x": 440, - "y": 1720, + "topicType": "str", + "x": 220, + "y": 1020, "wires": [ [ - "e531ffe3dcf34eb4" + "a7d233f984009e2e" ] ] }, { - "id": "4702a4a09124e27d", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "rotor_anglestart", - "label": "", + "id": "1d42cb9a63409283", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "", + "label": "Country Code 2", "tooltip": "", - "group": "d49a6dfd7fb17096", + "group": "8ab79a98e536e0d6", "order": 6, - "width": 3, + "width": 6, "height": 1, "passthru": false, - "outs": "end", - "topic": "", + "mode": "text", + "delay": "0", + "topic": "country", + "sendOnBlur": true, + "className": "", "topicType": "str", - "min": "-90", - "max": "90", - "step": "5", + "x": 240, + "y": 1060, + "wires": [ + [ + "a7d233f984009e2e" + ] + ] + }, + { + "id": "84ecaafd629c0f7a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "", + "group": "8ab79a98e536e0d6", + "order": 7, + "width": 0, + "height": 0, + "passthru": false, + "label": "Connect to Wifi", + "tooltip": "", + "color": "", + "bgcolor": "", "className": "", - "x": 440, - "y": 1760, + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "connect", + "topicType": "str", + "x": 240, + "y": 1100, "wires": [ [ - "9ce407cb16f0419a" + "a7d233f984009e2e" ] ] }, { - "id": "2cf946c7aab2cbb4", + "id": "6ea3cdab41f20f92", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "8ab79a98e536e0d6", + "order": 2, + "width": 0, + "height": 0, + "name": "", + "label": "Hotspot Mode", + "format": "{{msg.mode}}", + "layout": "row-spread", + "className": "", + "x": 240, + "y": 900, + "wires": [] + }, + { + "id": "a7d233f984009e2e", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "z": "e43a27722b508115", + "name": "function 1", + "func": "if (msg.topic == \"ssid\"){\n global.set('network_ssid',msg.payload)\n}\nelse if (msg.topic == \"password\"){\n global.set('network_password',msg.payload)\n}\nelse if (msg.topic == \"country\"){\n global.set('network_country',msg.payload)\n}\nelse if (msg.topic == \"connect\"){\n msg.ssid = global.get('network_ssid')\n msg.password = global.get('network_password')\n msg.country = global.get('network_country')\n msg.payload = \"\"\n return msg\n}", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 1720, + "x": 440, + "y": 980, "wires": [ [ - "94288df4c6756197" + "9b851aa999e86fd7", + "021dc780b478fee6", + "9ec0ad9fd3687e9f" ] ] }, { - "id": "e531ffe3dcf34eb4", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'rotor_anglemax'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 1720, + "id": "65518f3d4e3095e5", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 1", + "links": [ + "200d4b9951b6e066" + ], + "x": 85, + "y": 980, "wires": [ - [] + [ + "e51dd5e5c0f050d6", + "9959649037cb063b", + "1d42cb9a63409283" + ] ] }, { - "id": "4da5f650d3845baa", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "id": "9b851aa999e86fd7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\nfrom time import sleep\n\nsleep(0.5)\n\nerror = \"\"\nif msg['ssid'] == \"\":\n error = \"SSID, \"\nif msg['password'] == \"\" or len(msg['password'])<8:\n error = error + \"password, \"\nif msg['country'] == \"\" or len(msg['country']) != 2:\n error = error + \"country code\"\n\nif error != \"\":\n msg['payload'] = error\n msg['topic'] = \"Invalid Input(s):\"\n if check_hotspot_mode():\n msg['mode'] = True\n else:\n msg['mode'] = False\n return msg\n\n\nmsg['result'] = add_wifi_network(msg['ssid'],msg['password'],msg['country'])\n\nsleep(3)\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nmsg['topic'] = \"Added wifi & connected\"\nmsg['payload'] = \"changes might take a moment ;)\"\n\nreturn msg", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 1760, + "x": 670, + "y": 980, "wires": [ [ - "4702a4a09124e27d" + "c994c779e4bad800", + "11b19e9c6a4ffd8d", + "36890eb99a2ca1cf" ] ] }, { - "id": "9ce407cb16f0419a", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'rotor_anglestart'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "id": "11b19e9c6a4ffd8d", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "dialog", + "displayTime": "3", + "highlight": "", + "sendall": true, "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 1760, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "", + "name": "", + "x": 870, + "y": 980, "wires": [ [] ] }, { - "id": "fda776c5aa642867", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 9, - "width": 3, - "height": 1, - "name": "rotor_anglemax", - "label": "Max Angle", - "format": "", - "layout": "row-left", - "className": "", - "x": 780, - "y": 1720, - "wires": [] - }, - { - "id": "6e9af48a1c4c58c6", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "d49a6dfd7fb17096", - "order": 5, - "width": 3, - "height": 1, - "name": "rotor_anglestart", - "label": "Start Angle", - "format": "", - "layout": "row-left", - "className": "", - "x": 780, - "y": 1760, + "id": "021dc780b478fee6", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 3", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 640, + "y": 920, "wires": [] }, { - "id": "9b2bc9849aee310b", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "changeHostname", + "id": "c994c779e4bad800", + "type": "link out", + "z": "e43a27722b508115", + "name": "link out 2", + "mode": "link", "links": [ - "ec2db55a99bbe3ee", - "d5175561293ef490", - "960912e90ba5b5bc", - "50eeb3e362f9027f" + "592ec13d8f8923a9" ], - "x": 835, - "y": 900, - "wires": [ - [ - "8b9e3781511e9231" - ] - ] + "x": 815, + "y": 1020, + "wires": [] }, { - "id": "8b9e3781511e9231", + "id": "1eef47e0074545a9", "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "chk", - "func": "with open('/etc/hostname', 'r') as file:\n old_hostname = file.read().replace('\\n','')\nif old_hostname == 'raspberrypi':\n msg['hostname'] = 'openscan'\n msg['payload'] = 'OK'\n return msg", - "outputs": 1, - "x": 930, - "y": 900, - "wires": [ - [ - "ebce67b739d1891f" - ] - ] - }, - { - "id": "3fcbd9fe3acc3fb7", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "scan_arducam", - "group": "90223f7ddc082321", - "order": 1, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Focus Settings

MF - Manual Focus

By default, the switch is 'off', which means that autofocus is active. For small objects, it might be necessary to use manual focus: activate the switch and set the focus by pressing + and - accordingly. The distance is measured between the camera lens and the focal plane (which should be in the center or slightly in front of the center of the object). Be aware, that the distance value is only a rough estimate (mm)

ST - Stacking

Stacking is disabled by default. Once activated, you will be able to set the following:

Stacksize - defines the number of photos between the minimal and the maximal focal distance

SET press this button to set the maximal/minimal focal distance. Pressing the button a third time will re-set the values.

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 760, - "y": 160, + "z": "e43a27722b508115", + "name": "", + "func": "from OpenScan import add_wifi_network, check_hotspot_mode\n\nif check_hotspot_mode():\n msg['mode'] = True\nelse:\n msg['mode'] = False\n\nreturn msg", + "outputs": 2, + "x": 670, + "y": 1100, "wires": [ [ - "f304680180a23479" - ] + "c994c779e4bad800", + "36890eb99a2ca1cf" + ], + [] ] }, { - "id": "6d68cccec646e0a0", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "enable routine", - "func": "msg_enable = {}\nmsg_disable = {}\n\nmsg_enable['enabled'] = True\nmsg_disable['enabled'] = False\n\nif msg['payload'] == 'external':\n return msg_enable, msg_disable\nif msg['payload'] == 'gphoto':\n return msg_enable, msg_enable, msg_disable\n\nreturn msg_enable", - "outputs": 3, - "x": 560, - "y": 440, + "id": "434b04d8a65951ce", + "type": "inject", + "z": "e43a27722b508115", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 440, + "y": 1140, "wires": [ [ - "a0ba1aa77c5c8b7c" - ], - [ - "a42c12e94f65fa01" - ], - [ - "2d76e5617f13cd6c" + "1eef47e0074545a9" ] ] }, { - "id": "a0ba1aa77c5c8b7c", - "type": "link out", - "z": "017bd4e4a428bee5", + "id": "9ec0ad9fd3687e9f", + "type": "ui_toast", + "z": "e43a27722b508115", + "position": "bottom right", + "displayTime": "5", + "highlight": "", + "sendall": true, + "outputs": 0, + "ok": "OK", + "cancel": "", + "raw": false, + "className": "", + "topic": "Adding new Wifi", "name": "", - "mode": "link", - "links": [ - "2aea1727dbea76ce", - "4f212b44aa487945", - "65cef204b16f8741", - "917a194be245384a" - ], - "x": 675, - "y": 420, + "x": 670, + "y": 1020, "wires": [] }, { - "id": "a42c12e94f65fa01", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "2aea1727dbea76ce", - "4f212b44aa487945", - "65cef204b16f8741", - "917a194be245384a" - ], - "x": 715, - "y": 440, + "id": "36890eb99a2ca1cf", + "type": "debug", + "z": "e43a27722b508115", + "name": "debug 4", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 860, + "y": 940, "wires": [] }, { - "id": "2d76e5617f13cd6c", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "65cef204b16f8741" - ], - "x": 675, - "y": 460, - "wires": [] + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, + "wires": [ + [ + "85ad07b8f973bbe2" + ] + ] }, { - "id": "bd80ec228fb9a86d", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 135, - "y": 340, + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "endstop_angle", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2020, + "wires": [] + }, + { + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, "wires": [ - [ - "78351089ee9ebeaf", - "5fba78ae65eaaf5d", - "3492754252645e62", - "d16525a31223bc42", - "67206663b3881868" - ] + [] ] }, { - "id": "65b38bfeb3fee710", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 155, - "y": 760, + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, "wires": [ [ - "cc3cb10f2ea3f8b8" + "6b7245c3dcb694c8" ] ] }, { - "id": "d3fc91d87d5d5f62", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 135, - "y": 940, + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, "wires": [ [ - "725fd0cab0bddc0e" + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" ] ] }, { - "id": "cc9c4092edeb43cc", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 135, - "y": 1020, + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, "wires": [ [ - "27c6b221c90ed9e1", - "f393400.d87dcc" + "253feafa5a2f8b1d" ] ] }, { - "id": "f0b355967b33dfee", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 175, - "y": 1600, + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, "wires": [ - [ - "91fe20cb16f54293", - "2cf946c7aab2cbb4", - "4da5f650d3845baa", - "6659121906897a1f", - "15f02421b30a9ab6", - "58928befcc61b1f7", - "569829eeff715c33", - "c997e60519341afd", - "59ecf3a22cd3a669", - "27bc56f273360ac7", - "9b89eb1eaf333c10", - "2e8927be0e235fa1", - "f46ced86106306c8", - "4339704cd8552eb3", - "1ac53bb6150645fe", - "0d48bb415c584420", - "b6e420121e6466e7" - ] + [] ] }, { - "id": "d7c1fb4c028b21a5", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 155, - "y": 2280, + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_enable_endstop", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 1980, "wires": [ [ - "d5308090f2b7971a", - "694d1068bea15171", - "cec3e5e78a40476b", - "6f524f9370a18482", - "1f87f473e327c3cc", - "cff7ac5f1e061855", - "cf854461c37ca54f", - "ba10e04dd1761692", - "a69d216114f908a5", - "f02d4a036a225e87", - "1efd4a05aee0b86c", - "6841e5a392f0fb4f" + "69516440e3997111", + "f036424d79645761", + "fe62e12d458db2d4", + "aea4e51b20951560" ] ] }, { - "id": "a67c18aaca2f5fa5", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" - ], - "x": 155, - "y": 2900, + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, "wires": [ [ - "612cccacda1a65aa", - "954db931f87894ee", - "6682c8057e89d087", - "015be401d08047d2", - "1c6c0f8b9ac95659", - "dcee66c0d56c6934", - "6ec7d85bb17eb159", - "4f42d02a3776a006", - "3b126549c03a872e", - "58bbe9fc41e0d7b9" + "eefed04c25e3e4d6" ] ] }, { - "id": "c6d3821bc7f43f8e", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Reset default", - "group": "4fe6b4c0ade0938a", - "order": 14, - "width": 6, - "height": 1, - "passthru": false, - "label": "Restore default settings", - "tooltip": "", - "color": "red", - "bgcolor": "", + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, "className": "", - "icon": "", - "payload": "This can not be undone!", - "payloadType": "str", - "topic": "Restore default settings?", - "topicType": "str", - "x": 930, - "y": 300, + "x": 440, + "y": 440, "wires": [ [ - "e4be21c38b57f560" + "2aaf7c7f0f0c146f" ] ] }, { - "id": "e4be21c38b57f560", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 1090, - "y": 300, + "x": 660, + "y": 440, "wires": [ - [ - "9f30de04ced693d3" - ] + [] ] }, { - "id": "9f30de04ced693d3", + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.overwrite = true\nif(msg.payload == \"Yes\"){\n return msg}", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 1230, - "y": 300, + "x": 190, + "y": 3560, "wires": [ [ - "80bccc884b0be297" + "d0a1a4947a1137ca" ] ] }, { - "id": "80bccc884b0be297", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "38783aea9cc317a6" - ], - "x": 1325, - "y": 300, - "wires": [] + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 520, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] }, { - "id": "34b685aff2080d31", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "boot-cam", - "func": "from OpenScan import load_str\n\ncamera_modules = ('imx519', 'imx219', 'ov5647', 'imx477', 'imx378', 'ov9281', 'imx290a', 'imx290b')\n\npt1 = \"[all]\\n\\ncamera_auto_detect=0\\ngpu_mem=256\\ndtoverlay=vc4-fkms-v3d\\ndtoverlay=\"\npt3 = \",media-controller=1\\n\"\n\nwith open('/boot/config.txt', 'r') as file:\n config = file.read()\n\ncamera = load_str('camera')\nif camera not in camera_modules:\n msg['payload'] = 'no changes'\n return\n\nif camera == 'imx290a':\n camera = 'imx290,clock-frequency=37125000'\nelif camera == 'imx290b':\n camera = 'imx290,clock-frequency=74250000'\n\nconfig_keep = config.split('[all]\\n')[0]\nconfig_new = config_keep + pt1 + camera + pt3\n\nwith open('/boot/config.txt', 'w') as file:\n file.write(config_new)\n\nmsg['topic'] = 'Camera configuration changed'\nmsg['payload'] = 'Please restart the device'\n\nreturn msg", + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", "outputs": 1, - "x": 680, - "y": 500, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, "wires": [ [ - "68cba0c530c6def6" + "28eeaa3a8eb77679" ] ] }, { - "id": "68cba0c530c6def6", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 830, - "y": 500, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, "wires": [ [] ] }, { - "id": "f304680180a23479", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": true, + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, "className": "", - "topic": "", - "name": "Info", - "x": 1010, - "y": 120, + "topicType": "msg", + "x": 350, + "y": 3640, "wires": [ - [] + [ + "b5aba11033c5f952" + ] ] }, { - "id": "0d48bb415c584420", + "id": "058743d0e5afb87b", "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'turntable_mode'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 1640, - "wires": [ - [ - "ce215e159ce7267f" - ] - ] - }, - { - "id": "ce215e159ce7267f", - "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Turntable Mode", - "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 2, - "width": 6, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "", - "topicType": "str", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 440, - "y": 1640, + "x": 190, + "y": 3640, "wires": [ [ - "f95f528dec31425c" + "a26c0482377667c9" ] ] }, { - "id": "f95f528dec31425c", + "id": "b5aba11033c5f952", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'turntable_mode'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 1640, + "x": 550, + "y": 3640, "wires": [ [] ] }, { - "id": "4ebe5baece5ce9f2", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "preview_resolution", + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 5, - "width": 3, - "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0.5", - "max": "10", - "step": "0.5", + "color": "", + "bgcolor": "transparent", "className": "", - "x": 450, - "y": 2280, + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, "wires": [ [ - "60a415fff23cb55e" + "5fff689f9f8bc1ca" ] ] }, { - "id": "9ed0498cceceedde", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 4, - "width": 3, - "height": 1, - "name": "preview_res", - "label": "Preview Resolution (Mpx)", - "format": "", - "layout": "row-spread", - "className": "", - "x": 770, - "y": 2280, + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "69885a9ce218eb71", + "type": "comment", + "z": "e43a27722b508115", + "name": "Coloritos", + "info": "", + "x": 100, + "y": 3740, "wires": [] }, { - "id": "1efd4a05aee0b86c", + "id": "dc1cde67c3022e6b", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadI", - "func": "var file = 'cam_preview_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data)/1000000;\nreturn msg", + "func": "var file = 'interface_color'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 2280, + "x": 190, + "y": 3800, "wires": [ [ - "4ebe5baece5ce9f2" + "0dccca85770c7936" ] ] }, { - "id": "60a415fff23cb55e", + "id": "b63e8246ad14ad9d", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'cam_preview_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload*1000000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "interface-color", + "func": "var file = 'interface_color'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 2280, + "x": 540, + "y": 3800, "wires": [ [] ] }, { - "id": "6f3d403e157163e4", + "id": "b7044aa75196b521", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 3", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3800, + "wires": [ + [ + "dc1cde67c3022e6b" + ] + ] + }, + { + "id": "0dccca85770c7936", "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "Camera", + "z": "e43a27722b508115", + "name": "interface_color", "label": "", "tooltip": "", "place": "Select option", - "group": "1f7f7e1e24f5ad9b", - "order": 5, - "width": 4, - "height": 1, + "group": "15edc2ce885dddb3", + "order": 1, + "width": 0, + "height": 0, "passthru": true, "multiple": false, "options": [ { - "label": "Pi Cam v1 - 5mp", - "value": "ov5647", - "type": "str" - }, - { - "label": "Pi Cam v2 - 8mp", - "value": "imx219", - "type": "str" - }, - { - "label": "Pi Cam HQ - 12.3mp", - "value": "imx477", - "type": "str" - }, - { - "label": "Arducam IMX519 - 16mp", - "value": "imx519", - "type": "str" - }, - { - "label": "IMX290 a", - "value": "imx290a", + "label": "Aburrido", + "value": "#097479", "type": "str" }, { - "label": "IMX290 b", - "value": "imx290b", + "label": "Morado", + "value": "#790974", "type": "str" }, { - "label": "IMX378", - "value": "imx378", + "label": "Berenjena", + "value": "#79093c", "type": "str" }, { - "label": "OV9281", - "value": "ov9281", + "label": "Azul", + "value": "#093c79 ", "type": "str" }, { - "label": "DSLR (gphoto)", - "value": "gphoto", - "type": "str" - }, - { - "label": "USB Webcam", - "value": "usb_webcam", - "type": "str" - }, - { - "label": "External Camera", - "value": "external", + "label": "Oliva", + "value": "#747909", "type": "str" } ], @@ -10054,154 +8676,133 @@ "topic": "topic", "topicType": "msg", "className": "", - "x": 400, - "y": 460, + "x": 360, + "y": 3800, "wires": [ [ - "6d68cccec646e0a0", - "4058a31e942e8f95" + "b63e8246ad14ad9d" ] ] }, { - "id": "c6138801b30f091d", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "model", - "label": "", - "tooltip": "", - "place": "Select option", - "group": "1f7f7e1e24f5ad9b", - "order": 3, - "width": 4, - "height": 1, - "passthru": true, - "multiple": false, - "options": [ - { - "label": "Please Select", - "value": "None", - "type": "str" - }, - { - "label": "OpenScan Mini", - "value": "OSMini", - "type": "str" - }, - { - "label": "OpenScan Classic", - "value": "OSClassic", - "type": "str" - } - ], - "payload": "", - "topic": "topic", - "topicType": "msg", - "className": "", - "x": 390, - "y": 580, + "id": "667950f6671bd1a0", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'hostname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 210, + "y": 840, "wires": [ [ - "896242c5a7e50fa7" + "b82a1cbefad51cd8" ] ] }, { - "id": "4da67c23c7a543a0", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "1f7f7e1e24f5ad9b", - "order": 4, - "width": 2, - "height": 1, - "name": "", - "label": "Camera", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 840, - "y": 460, - "wires": [] - }, - { - "id": "1fed8676078ea9a7", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "1f7f7e1e24f5ad9b", - "order": 2, - "width": 2, - "height": 1, - "name": "", - "label": "Model", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 730, - "y": 580, - "wires": [] - }, - { - "id": "a4b7eea9a9736b0a", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Update&Info", - "group": "ddbd496e.93a288", - "order": 1, - "width": 6, - "height": 1, - "passthru": false, - "label": "", + "id": "5f32d7e78e368454", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'hostname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 510, + "y": 840, + "wires": [ + [] + ] + }, + { + "id": "b82a1cbefad51cd8", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "hostname", + "label": "Hostname", "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", - "payloadType": "str", + "group": "8ab79a98e536e0d6", + "order": 1, + "width": 0, + "height": 0, + "passthru": true, + "mode": "text", + "delay": 300, "topic": "topic", + "sendOnBlur": true, + "className": "", "topicType": "msg", - "x": 750, - "y": 200, + "x": 360, + "y": 840, "wires": [ [ - "f304680180a23479" + "5f32d7e78e368454" ] ] }, { - "id": "b6e420121e6466e7", + "id": "5fd155711e29b1b8", + "type": "comment", + "z": "e43a27722b508115", + "name": "Monitoring", + "info": "", + "x": 100, + "y": 3860, + "wires": [] + }, + { + "id": "815702499384f118", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadB", - "func": "var file = 'routine_secondpass'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "func": "var file = 'datadog_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 290, - "y": 1600, + "x": 190, + "y": 3920, "wires": [ [ - "ab8d5cfe9190bb5f" + "bfdbdae28bf42ed4" ] ] }, { - "id": "ab8d5cfe9190bb5f", + "id": "464c8495f86daaa7", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "datadog_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('datadog_enable'):\n save('datadog_enable', state)\n", + "outputs": 1, + "x": 520, + "y": 3920, + "wires": [ + [] + ] + }, + { + "id": "bfdbdae28bf42ed4", "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Second pass", - "tooltip": "", - "group": "d49a6dfd7fb17096", - "order": 3, - "width": 6, - "height": 1, + "z": "e43a27722b508115", + "name": "datadog_enable", + "label": "Enable Datadog", + "tooltip": "Enable Datadog monitoring", + "group": "33aff36289823faa", + "order": 1, + "width": "6", + "height": "1", "passthru": true, "decouple": "false", - "topic": "", - "topicType": "str", + "topic": "topic", + "topicType": "msg", "style": "", "onvalue": "true", "onvalueType": "bool", @@ -10213,206 +8814,348 @@ "offcolor": "", "animate": false, "className": "", - "x": 430, - "y": 1600, + "x": 340, + "y": 3920, + "wires": [ + [ + "464c8495f86daaa7" + ] + ] + }, + { + "id": "f93ce2d26953341f", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "datadog_api_token", + "label": "Datadog Api Token", + "tooltip": "Datadog Api Token", + "group": "33aff36289823faa", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3960, "wires": [ [ - "fa51327f0140b045" + "647641e79884eb87" ] ] }, { - "id": "fa51327f0140b045", + "id": "ee668e39d213070b", "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'routine_secondpass'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'datadog_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 630, - "y": 1600, + "x": 190, + "y": 3960, + "wires": [ + [ + "f93ce2d26953341f" + ] + ] + }, + { + "id": "647641e79884eb87", + "type": "function", + "z": "e43a27722b508115", + "name": "datadog_api_token", + "func": "var file = 'datadog_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3960, + "wires": [ + [] + ] + }, + { + "id": "ff2dea1ab9cb7776", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 4", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3960, + "wires": [ + [ + "815702499384f118", + "ee668e39d213070b" + ] + ] + }, + { + "id": "a1b81e7fe94ad4e5", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "", + "func": "import subprocess\nsubprocess.run([\"systemctl\",\"restart\",\"nodered\"])\nreturn msg", + "outputs": 1, + "x": 530, + "y": 3740, "wires": [ [] ] }, { - "id": "6841e5a392f0fb4f", + "id": "2f3a3c0e682ae862", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "restart_interface", + "group": "15edc2ce885dddb3", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "Restart Interface", + "tooltip": "", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 340, + "y": 3740, + "wires": [ + [ + "a1b81e7fe94ad4e5" + ] + ] + }, + { + "id": "fe62e12d458db2d4", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "loadB", - "func": "var file = 'cam_output_downscale'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "func": "var file = 'rotor_endstop_pushed'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = false;\n}\nelse{\n data = true;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 290, - "y": 2320, + "y": 2060, "wires": [ [ - "110216d678fad14f" + "96e2b45a7102156b" ] ] }, { - "id": "110216d678fad14f", + "id": "96e2b45a7102156b", "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Downscale output", + "z": "e43a27722b508115", + "name": "rotor_endstop_pushed", + "label": "", "tooltip": "", - "group": "93aadb71dee6d977", - "order": 6, - "width": 6, + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, "height": 1, "passthru": true, "decouple": "false", - "topic": "", - "topicType": "str", + "topic": "topic", + "topicType": "msg", "style": "", - "onvalue": "true", + "onvalue": "false", "onvalueType": "bool", "onicon": "", "oncolor": "", - "offvalue": "false", + "offvalue": "true", "offvalueType": "bool", "officon": "", "offcolor": "", "animate": false, "className": "", - "x": 450, - "y": 2320, + "x": 460, + "y": 2060, "wires": [ [ - "214d548d564f8ba2" + "df66caa5e0497e65" ] ] }, { - "id": "214d548d564f8ba2", + "id": "df66caa5e0497e65", "type": "function", - "z": "017bd4e4a428bee5", + "z": "e43a27722b508115", "name": "write", - "func": "var file = 'cam_output_downscale'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n \nmsg.enabled = msg.payload\nreturn msg", + "func": "var file = 'rotor_endstop_pushed'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 630, - "y": 2320, + "y": 2060, "wires": [ - [ - "1becbff4884b8c1a" - ] + [] ] }, { - "id": "8be1ca844a6caa54", - "type": "ui_slider", - "z": "017bd4e4a428bee5", - "name": "output_resolution", - "label": "", - "tooltip": "", - "group": "93aadb71dee6d977", - "order": 8, + "id": "aea4e51b20951560", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, "width": 3, "height": 1, - "passthru": false, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0.5", - "max": "20", - "step": "0.5", + "name": "rotor_endstop_pushed", + "label": "Reverse Endstop", + "format": "", + "layout": "row-left", "className": "", - "x": 450, - "y": 2360, + "x": 800, + "y": 2060, + "wires": [] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'meanwhile'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, "wires": [ [ - "a6b2c0a0604ccf14" + "e23c514008cad1a1" ] ] }, { - "id": "9ac09d89d791e953", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "93aadb71dee6d977", - "order": 7, - "width": 3, - "height": 1, - "name": "image_res", - "label": "Output Resolution (Mpx)", - "format": "", - "layout": "row-spread", - "className": "", - "x": 770, - "y": 2360, - "wires": [] + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] }, { - "id": "1becbff4884b8c1a", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadI", - "func": "var file = 'cam_output_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data)/1000000;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 2360, + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, "wires": [ [ - "8be1ca844a6caa54" + "4ce127c61c3c5966", + "beacc3dc5398fa79" ] ] }, { - "id": "a6b2c0a0604ccf14", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'cam_output_resolution'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload*1000000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", + "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 630, - "y": 2360, + "x": 290, + "y": 220, "wires": [ [] ] }, { - "id": "f358de1e64b491bb", + "id": "beacc3dc5398fa79", "type": "link out", - "z": "017bd4e4a428bee5", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ - "b30d918661392ab3", - "44c598049cd533fd" + "38783aea9cc317a6" ], - "x": 635, - "y": 620, + "x": 195, + "y": 260, + "wires": [] + }, + { + "id": "e23c514008cad1a1", + "type": "debug", + "z": "a5557543ccff5889", + "name": "debug 1", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "true", + "targetType": "full", + "statusVal": "", + "statusType": "auto", + "x": 480, + "y": 140, "wires": [] }, { "id": "b0629875a30ae1d7", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "get update", - "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", "outputs": 2, - "x": 350, - "y": 240, + "x": 390, + "y": 540, "wires": [ [ "1bbe2d769f42c313" @@ -10425,7 +9168,7 @@ { "id": "c7b6d05a62172432", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "ddbd496e.93a288", "order": 3, "width": 0, @@ -10435,19 +9178,19 @@ "format": "{{msg.status}}", "layout": "row-spread", "className": "", - "x": 170, - "y": 100, + "x": 210, + "y": 400, "wires": [] }, { "id": "fefe45404bdb19c4", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "check files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", "outputs": 1, - "x": 510, - "y": 260, + "x": 550, + "y": 560, "wires": [ [ "1bbe2d769f42c313", @@ -10458,14 +9201,14 @@ { "id": "d0104e0163745993", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "links": [ "960912e90ba5b5bc", "50eeb3e362f9027f" ], - "x": 75, - "y": 140, + "x": 115, + "y": 440, "wires": [ [ "ec30638407332e43", @@ -10477,7 +9220,7 @@ { "id": "ec30638407332e43", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "loadS", "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", "outputs": 1, @@ -10485,8 +9228,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 180, + "x": 210, + "y": 480, "wires": [ [ "2852023f3aa8db10" @@ -10496,7 +9239,7 @@ { "id": "2852023f3aa8db10", "type": "ui_dropdown", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "label": "", "tooltip": "", @@ -10510,21 +9253,26 @@ "options": [ { "label": "stable", - "value": "main", + "value": "stable", "type": "str" }, { "label": "beta", "value": "beta", "type": "str" + }, + { + "label": "meanwhile", + "value": "meanwhile", + "type": "str" } ], "payload": "", "topic": "topic", "topicType": "msg", "className": "", - "x": 300, - "y": 180, + "x": 340, + "y": 480, "wires": [ [ "1e10b387ee30c486" @@ -10534,7 +9282,7 @@ { "id": "1e10b387ee30c486", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "write", "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -10542,8 +9290,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 430, - "y": 180, + "x": 470, + "y": 480, "wires": [ [] ] @@ -10551,7 +9299,7 @@ { "id": "274129c51b0b87ef", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "ddbd496e.93a288", "order": 4, "width": 4, @@ -10561,14 +9309,14 @@ "format": "{{msg.payload}}", "layout": "row-spread", "className": "", - "x": 570, - "y": 180, + "x": 610, + "y": 480, "wires": [] }, { "id": "51cd8c8643e6b46a", "type": "ui_switch", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "label": "Auto-check update availability", "tooltip": "", @@ -10591,8 +9339,8 @@ "offcolor": "", "animate": false, "className": "", - "x": 370, - "y": 140, + "x": 410, + "y": 440, "wires": [ [ "1ab4c6b4b232a022" @@ -10602,7 +9350,7 @@ { "id": "38cbf7965d1c1834", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "loadB", "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, @@ -10610,8 +9358,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 140, + "x": 210, + "y": 440, "wires": [ [ "51cd8c8643e6b46a" @@ -10621,7 +9369,7 @@ { "id": "1ab4c6b4b232a022", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "write", "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", "outputs": 1, @@ -10629,8 +9377,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 570, - "y": 140, + "x": 610, + "y": 440, "wires": [ [] ] @@ -10638,7 +9386,7 @@ { "id": "ae92a328af306ebb", "type": "ui_toast", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "position": "dialog", "displayTime": "3", "highlight": "", @@ -10650,8 +9398,8 @@ "className": "", "topic": "", "name": "", - "x": 670, - "y": 260, + "x": 710, + "y": 560, "wires": [ [ "2de63e8e3ae5fb0c", @@ -10662,14 +9410,14 @@ { "id": "cbd0afc4aa7b302a", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "update status", "links": [ "1bbe2d769f42c313", "42061b28cff81f99" ], - "x": 75, - "y": 100, + "x": 115, + "y": 400, "wires": [ [ "c7b6d05a62172432", @@ -10680,20 +9428,20 @@ { "id": "1bbe2d769f42c313", "type": "link out", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ "cbd0afc4aa7b302a" ], - "x": 625, - "y": 220, + "x": 665, + "y": 520, "wires": [] }, { "id": "7cf60615d93e696b", "type": "ui_button", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "group": "ddbd496e.93a288", "order": 7, @@ -10710,8 +9458,8 @@ "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 140, - "y": 260, + "x": 180, + "y": 560, "wires": [ [ "b0629875a30ae1d7" @@ -10721,12 +9469,12 @@ { "id": "2de63e8e3ae5fb0c", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "download files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", "outputs": 1, - "x": 840, - "y": 260, + "x": 880, + "y": 560, "wires": [ [ "42061b28cff81f99", @@ -10737,7 +9485,7 @@ { "id": "929281fef53e09f8", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "msg", "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", "outputs": 1, @@ -10745,8 +9493,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 810, - "y": 220, + "x": 850, + "y": 520, "wires": [ [ "42061b28cff81f99" @@ -10756,20 +9504,20 @@ { "id": "42061b28cff81f99", "type": "link out", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ "cbd0afc4aa7b302a" ], - "x": 955, - "y": 220, + "x": 995, + "y": 520, "wires": [] }, { "id": "49f1ecb29a3f84f4", "type": "function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "loadB", "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", "outputs": 1, @@ -10777,8 +9525,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 170, - "y": 220, + "x": 210, + "y": 520, "wires": [ [ "b0629875a30ae1d7" @@ -10788,27 +9536,28 @@ { "id": "fe3a855fee9e28c6", "type": "link out", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "mode": "link", "links": [ - "9bb0adbd716ce347" + "9bb0adbd716ce347", + "01c882fcc51b349c" ], - "x": 955, - "y": 260, + "x": 995, + "y": 560, "wires": [] }, { "id": "5e7d5e4335d37794", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "links": [ "960912e90ba5b5bc", "50eeb3e362f9027f" ], - "x": 55, - "y": 400, + "x": 95, + "y": 700, "wires": [ [ "2bb5fe78e09fec8a" @@ -10818,12 +9567,12 @@ { "id": "2bb5fe78e09fec8a", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "msg", "func": "\nfrom subprocess import getoutput\nimport os\n\nmsg['os'] = getoutput(\"cat /etc/os-release | grep -i 'PRETTY_NAME'\")[13:-1]\nmsg['device'] = getoutput(\"cat /proc/device-tree/model\")\nmsg['flask'] = getoutput(\"systemctl status flask |grep -i 'Active:'\").split(' ')[6]\nmsg['osdate'] = getoutput(\"vcgencmd version\").split('\\n')[0]\nmsg['temp'] = getoutput(\"vcgencmd measure_temp\").split('=')[1]\ncpu_total = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $2}'\")\ncpu_used = getoutput(\"free -m | head -n2 | tail -n1 |awk '{print $3}'\")\nswap_total = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $2}'\")\nswap_used = getoutput(\"free -m | head -n3 | tail -n1 |awk '{print $3}'\")\ndiskspace_used = getoutput(\"df -h / | tail -n1 |awk '{print $3}'\")\ndiskspace_total = getoutput(\"df -h / | tail -n1 |awk '{print $2}'\")\n\nmsg['cpu'] = cpu_used + '/' + cpu_total + 'MB'\nmsg['swap'] = swap_used + '/' + swap_total + 'MB'\nmsg['diskspace'] =diskspace_used + '/' + diskspace_total\n\nif msg['flask'] == 'inactive':\n os.system('systemctl restart flask')\n\nreturn msg", "outputs": 1, - "x": 170, - "y": 400, + "x": 210, + "y": 700, "wires": [ [ "dbc77052ac950624", @@ -10841,7 +9590,7 @@ { "id": "d97c3068ef5fef96", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 2, "width": 0, @@ -10851,14 +9600,14 @@ "format": "{{msg.os}}", "layout": "row-spread", "className": "", - "x": 450, - "y": 440, + "x": 490, + "y": 740, "wires": [] }, { "id": "73a3b828f862312b", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 8, "width": 0, @@ -10868,14 +9617,14 @@ "format": "{{msg.flask}}", "layout": "row-spread", "className": "", - "x": 450, - "y": 480, + "x": 490, + "y": 780, "wires": [] }, { "id": "dbc77052ac950624", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 1, "width": 0, @@ -10885,59 +9634,17 @@ "format": "{{msg.device}}", "layout": "row-spread", "className": "", - "x": 460, - "y": 400, + "x": 500, + "y": 700, "wires": [] }, - { - "id": "4c7fa5b5b27b83a5", - "type": "python3-function", - "z": "c8e7ecb5849edb9a", - "name": "create beta new", - "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'beta'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\ndel msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/Arducam.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/Arducam.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/OpenScan.py'\nmsg[scope]['3']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/config.txt'\nmsg[scope]['4']['dst'] = '/boot/config.txt'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/flows.json'\nmsg[scope]['5']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['6'] = {}\nmsg[scope]['6']['src'] = scope + '/settings.js'\nmsg[scope]['6']['dst'] = '/root/.node-red/settings.js'\n\nmsg[scope]['7'] = {}\nmsg[scope]['7']['src'] = 'files/logo.jpg'\nmsg[scope]['7']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", - "outputs": 1, - "x": 300, - "y": 820, - "wires": [ - [] - ] - }, - { - "id": "80175eb8dc6ad009", - "type": "inject", - "z": "c8e7ecb5849edb9a", - "name": "", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "", - "payloadType": "date", - "x": 140, - "y": 820, - "wires": [ - [ - "4c7fa5b5b27b83a5" - ] - ] - }, { "id": "3f42560297fe6978", "type": "ui_template", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "name": "Download LOG", - "order": 9, + "order": 10, "width": 6, "height": 1, "format": "\n
Download error log\n
\n", @@ -10946,8 +9653,8 @@ "resendOnRefresh": false, "templateScope": "local", "className": "", - "x": 140, - "y": 760, + "x": 180, + "y": 1060, "wires": [ [] ] @@ -10955,12 +9662,12 @@ { "id": "c94623ddd9d95f78", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "get update", "func": "from OpenScan import save\n\nif msg['status'] == \"No new update available\":\n save('updateable',False)\nelif msg['status'] == \"New update available\":\n save('updateable',True)\n", "outputs": 1, - "x": 170, - "y": 60, + "x": 210, + "y": 360, "wires": [ [] ] @@ -10968,13 +9675,13 @@ { "id": "39a502b38837273d", "type": "link in", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "links": [ "1e7457ea9c2c5e09" ], - "x": 205, - "y": 300, + "x": 245, + "y": 600, "wires": [ [ "b0629875a30ae1d7" @@ -10984,7 +9691,7 @@ { "id": "901e31453b2bdff8", "type": "delay", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "pauseType": "delay", "timeout": "10", @@ -10998,8 +9705,8 @@ "drop": false, "allowrate": false, "outputs": 1, - "x": 180, - "y": 440, + "x": 220, + "y": 740, "wires": [ [ "2bb5fe78e09fec8a" @@ -11009,7 +9716,7 @@ { "id": "f983854748ee4763", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 3, "width": 0, @@ -11019,14 +9726,14 @@ "format": "{{msg.osdate}}", "layout": "row-spread", "className": "", - "x": 450, - "y": 520, + "x": 490, + "y": 820, "wires": [] }, { "id": "5347c7c517f5e8c7", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 4, "width": 0, @@ -11036,14 +9743,14 @@ "format": "{{msg.temp}}", "layout": "row-spread", "className": "", - "x": 470, - "y": 560, + "x": 510, + "y": 860, "wires": [] }, { "id": "3a5016f7003cd72c", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 5, "width": 0, @@ -11053,14 +9760,14 @@ "format": "{{msg.cpu}}", "layout": "row-spread", "className": "", - "x": 480, - "y": 600, + "x": 520, + "y": 900, "wires": [] }, { "id": "6d720c4a4ecd9475", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 6, "width": 0, @@ -11070,14 +9777,14 @@ "format": "{{msg.swap}}", "layout": "row-spread", "className": "", - "x": 480, - "y": 640, + "x": 520, + "y": 940, "wires": [] }, { "id": "6438b7d060a70d81", "type": "ui_text", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "group": "3ce32450.e0cffc", "order": 7, "width": 0, @@ -11087,70 +9794,14 @@ "format": "{{msg.diskspace}}", "layout": "row-spread", "className": "", - "x": 470, - "y": 680, - "wires": [] - }, - { - "id": "d7362e6e0ec7bdaa", - "type": "inject", - "z": "c8e7ecb5849edb9a", - "name": "", - "props": [ - { - "p": "overwrite", - "v": "true", - "vt": "bool" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "x": 130, - "y": 900, - "wires": [ - [ - "4ce127c61c3c5966", - "beacc3dc5398fa79" - ] - ] - }, - { - "id": "4ce127c61c3c5966", - "type": "python3-function", - "z": "c8e7ecb5849edb9a", - "name": "prepare image creation", - "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", - "outputs": 1, - "x": 330, - "y": 900, - "wires": [ - [] - ] - }, - { - "id": "beacc3dc5398fa79", - "type": "link out", - "z": "c8e7ecb5849edb9a", - "name": "", - "mode": "link", - "links": [ - "38783aea9cc317a6" - ], - "x": 235, - "y": 940, + "x": 510, + "y": 980, "wires": [] }, { "id": "8d012912f302be85", "type": "ui_button", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "", "group": "ddbd496e.93a288", "order": 8, @@ -11167,8 +9818,8 @@ "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 170, - "y": 340, + "x": 210, + "y": 640, "wires": [ [ "5242607a723cc628" @@ -11178,12 +9829,12 @@ { "id": "5242607a723cc628", "type": "python3-function", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "name": "Changelog", - "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/OpenScan-org/OpenScan-Doc/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", "outputs": 1, - "x": 390, - "y": 340, + "x": 430, + "y": 640, "wires": [ [ "573722197b15bf84" @@ -11193,7 +9844,7 @@ { "id": "573722197b15bf84", "type": "ui_toast", - "z": "c8e7ecb5849edb9a", + "z": "a5557543ccff5889", "position": "dialog", "displayTime": "3", "highlight": "", @@ -11205,8 +9856,49 @@ "className": "", "topic": "", "name": "", - "x": 570, - "y": 340, + "x": 610, + "y": 640, + "wires": [ + [] + ] + }, + { + "id": "cde61b7de9eeaba7", + "type": "ui_button", + "z": "a5557543ccff5889", + "name": "", + "group": "3ce32450.e0cffc", + "order": 9, + "width": 0, + "height": 0, + "passthru": false, + "label": "Expand Root", + "tooltip": "Sets the maximum space your SD card admits", + "color": "", + "bgcolor": "", + "className": "", + "icon": "", + "payload": "expand", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 510, + "y": 1020, + "wires": [ + [ + "eab36487d201f867" + ] + ] + }, + { + "id": "eab36487d201f867", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "", + "func": "import subprocess\nsubprocess.run([\"raspi-config\",\"--expand-rootfs\"])\nreturn msg", + "outputs": 1, + "x": 690, + "y": 1020, "wires": [ [] ] diff --git a/update/meanwhile/settings.js b/update/meanwhile/settings.js new file mode 100644 index 0000000..357b02b --- /dev/null +++ b/update/meanwhile/settings.js @@ -0,0 +1,512 @@ +/** + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT + * + * It can contain any valid JavaScript code that will get run when Node-RED + * is started. + * + * Lines that start with // are commented out. + * Each entry should be separated from the entries above and below by a comma ',' + * + * For more information about individual settings, refer to the documentation: + * https://nodered.org/docs/user-guide/runtime/configuration + * + * The settings are split into the following sections: + * - Flow File and User Directory Settings + * - Security + * - Server Settings + * - Runtime Settings + * - Editor Settings + * - Node Settings + * + **/ +process.env.HOSTNAME = require('os').hostname(); + +module.exports = { + +/******************************************************************************* + * Flow File and User Directory Settings + * - flowFile + * - credentialSecret + * - flowFilePretty + * - userDir + * - nodesDir + ******************************************************************************/ + + /** The file containing the flows. If not set, defaults to flows_.json **/ + flowFile: "flows.json", + + /** By default, credentials are encrypted in storage using a generated key. To + * specify your own secret, set the following property. + * If you want to disable encryption of credentials, set this property to false. + * Note: once you set this property, do not change it - doing so will prevent + * node-red from being able to decrypt your existing credentials and they will be + * lost. + */ + credentialSecret: false, + + /** By default, the flow JSON will be formatted over multiple lines making + * it easier to compare changes when using version control. + * To disable pretty-printing of the JSON set the following property to false. + */ + flowFilePretty: true, + + /** By default, all user data is stored in a directory called `.node-red` under + * the user's home directory. To use a different location, the following + * property can be used + */ + //userDir: '/home/nol/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + + /** Node-RED scans the `nodes` directory in the userDir to find local node files. + * The following property can be used to specify an additional directory to scan. + */ + //nodesDir: '/home/nol/.node-red/nodes', + +/******************************************************************************* + * Security + * - adminAuth + * - https + * - httpsRefreshInterval + * - requireHttps + * - httpNodeAuth + * - httpStaticAuth + ******************************************************************************/ + + /** To password protect the Node-RED editor and admin API, the following + * property can be used. See http://nodered.org/docs/security.html for details. + */ + //adminAuth: { + // type: "credentials", + // users: [{ + // username: "admin", + // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", + // permissions: "*" + // }] + //}, + + /** The following property can be used to enable HTTPS + * This property can be either an object, containing both a (private) key + * and a (public) certificate, or a function that returns such an object. + * See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener + * for details of its contents. + */ + + /** Option 1: static object */ + //https: { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + //}, + + /** Option 2: function that returns the HTTP configuration object */ + // https: function() { + // // This function should return the options object, or a Promise + // // that resolves to the options object + // return { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + // } + // }, + + /** If the `https` setting is a function, the following setting can be used + * to set how often, in hours, the function will be called. That can be used + * to refresh any certificates. + */ + //httpsRefreshInterval : 12, + + /** The following property can be used to cause insecure HTTP connections to + * be redirected to HTTPS. + */ + //requireHttps: true, + + /** To password protect the node-defined HTTP endpoints (httpNodeRoot), + * including node-red-dashboard, or the static content (httpStatic), the + * following properties can be used. + * The `pass` field is a bcrypt hash of the password. + * See http://nodered.org/docs/security.html#generating-the-password-hash + */ + //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + +/******************************************************************************* + * Server Settings + * - uiPort + * - uiHost + * - apiMaxLength + * - httpServerOptions + * - httpAdminRoot + * - httpAdminMiddleware + * - httpNodeRoot + * - httpNodeCors + * - httpNodeMiddleware + * - httpStatic + * - httpStaticRoot + ******************************************************************************/ + + /** the tcp port that the Node-RED web server is listening on */ + uiPort: process.env.PORT || 80, + + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. + * To listen on all IPv6 addresses, set uiHost to "::", + * The following property can be used to listen on a specific interface. For + * example, the following would only allow connections from the local machine. + */ + //uiHost: "127.0.0.1", + + /** The maximum size of HTTP request that will be accepted by the runtime api. + * Default: 5mb + */ + //apiMaxLength: '5mb', + + /** The following property can be used to pass custom options to the Express.js + * server used by Node-RED. For a full list of available options, refer + * to http://expressjs.com/en/api.html#app.settings.table + */ + //httpServerOptions: { }, + + /** By default, the Node-RED UI is available at http://localhost:1880/ + * The following property can be used to specify a different root path. + * If set to false, this is disabled. + */ + httpAdminRoot: '/editor', + + /** The following property can be used to add a custom middleware function + * in front of all admin http routes. For example, to set custom http + * headers. It can be a single function or an array of middleware functions. + */ + // httpAdminMiddleware: function(req,res,next) { + // // Set the X-Frame-Options header to limit where the editor + // // can be embedded + // //res.set('X-Frame-Options', 'sameorigin'); + // next(); + // }, + + + /** Some nodes, such as HTTP In, can be used to listen for incoming http requests. + * By default, these are served relative to '/'. The following property + * can be used to specifiy a different root path. If set to false, this is + * disabled. + */ + //httpNodeRoot: '/red-nodes', + + /** The following property can be used to configure cross-origin resource sharing + * in the HTTP nodes. + * See https://github.com/troygoode/node-cors#configuration-options for + * details on its contents. The following is a basic permissive set of options: + */ + //httpNodeCors: { + // origin: "*", + // methods: "GET,PUT,POST,DELETE" + //}, + + /** If you need to set an http proxy please set an environment variable + * called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. + * For example - http_proxy=http://myproxy.com:8080 + * (Setting it here will have no effect) + * You may also specify no_proxy (or NO_PROXY) to supply a comma separated + * list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk + */ + + /** The following property can be used to add a custom middleware function + * in front of all http in nodes. This allows custom authentication to be + * applied to all http in nodes, or any other sort of common request processing. + * It can be a single function or an array of middleware functions. + */ + //httpNodeMiddleware: function(req,res,next) { + // // Handle/reject the request, or pass it on to the http in node by calling next(); + // // Optionally skip our rawBodyParser by setting this to true; + // //req.skipRawBodyParser = true; + // next(); + //}, + + /** When httpAdminRoot is used to move the UI to a different root path, the + * following property can be used to identify a directory of static content + * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot + */ + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + +/******************************************************************************* + * Runtime Settings + * - lang + * - logging + * - contextStorage + * - exportGlobalContextKeys + * - externalModules + ******************************************************************************/ + + /** Uncomment the following to run node-red in your preferred language. + * Available languages include: en-US (default), ja, de, zh-CN, zh-TW, ru, ko + * Some languages are more complete than others. + */ + // lang: "de", + + /** Configure the logging output */ + logging: { + /** Only console logging is currently supported */ + console: { + /** Level of logging to be recorded. Options are: + * fatal - only those errors which make the application unusable should be recorded + * error - record errors which are deemed fatal for a particular request + fatal errors + * warn - record problems which are non fatal + errors + fatal errors + * info - record information about the general running of the application + warn + error + fatal errors + * debug - record information which is more verbose than info + info + warn + error + fatal errors + * trace - record very detailed logging + debug + info + warn + error + fatal errors + * off - turn off all logging (doesn't affect metrics or audit) + */ + level: "info", + /** Whether or not to include metric events in the log output */ + metrics: false, + /** Whether or not to include audit events in the log output */ + audit: false + } + }, + + /** Context Storage + * The following property can be used to enable context storage. The configuration + * provided here will enable file-based context that flushes to disk every 30 seconds. + * Refer to the documentation for further options: https://nodered.org/docs/api/context/ + */ + //contextStorage: { + // default: { + // module:"localfilesystem" + // }, + //}, + + /** `global.keys()` returns a list of all properties set in global context. + * This allows them to be displayed in the Context Sidebar within the editor. + * In some circumstances it is not desirable to expose them to the editor. The + * following property can be used to hide any property set in `functionGlobalContext` + * from being list by `global.keys()`. + * By default, the property is set to false to avoid accidental exposure of + * their values. Setting this to true will cause the keys to be listed. + */ + exportGlobalContextKeys: false, + + /** Configure how the runtime will handle external npm modules. + * This covers: + * - whether the editor will allow new node modules to be installed + * - whether nodes, such as the Function node are allowed to have their + * own dynamically configured dependencies. + * The allow/denyList options can be used to limit what modules the runtime + * will install/load. It can use '*' as a wildcard that matches anything. + */ + externalModules: { + // autoInstall: false, /** Whether the runtime will attempt to automatically install missing modules */ + // autoInstallRetry: 30, /** Interval, in seconds, between reinstall attempts */ + // palette: { /** Configuration for the Palette Manager */ + // allowInstall: true, /** Enable the Palette Manager in the editor */ + // allowUpload: true, /** Allow module tgz files to be uploaded and installed */ + // allowList: [], + // denyList: [] + // }, + // modules: { /** Configuration for node-specified modules */ + // allowInstall: true, + // allowList: [], + // denyList: [] + // } + }, + + +/******************************************************************************* + * Editor Settings + * - disableEditor + * - editorTheme + ******************************************************************************/ + + /** The following property can be used to disable the editor. The admin API + * is not affected by this option. To disable both the editor and the admin + * API, use either the httpRoot or httpAdminRoot properties + */ + //disableEditor: false, + + /** Customising the editor + * See https://nodered.org/docs/user-guide/runtime/configuration#editor-themes + * for all available options. + */ + editorTheme: { + /** The following property can be used to set a custom theme for the editor. + * See https://github.com/node-red-contrib-themes/theme-collection for + * a collection of themes to chose from. + */ + //theme: "", + palette: { + /** The following property can be used to order the categories in the editor + * palette. If a node's category is not in the list, the category will get + * added to the end of the palette. + * If not set, the following default order is used: + */ + //categories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], + }, + projects: { + /** To enable the Projects feature, set this value to true */ + enabled: false, + workflow: { + /** Set the default projects workflow mode. + * - manual - you must manually commit changes + * - auto - changes are automatically committed + * This can be overridden per-user from the 'Git config' + * section of 'User Settings' within the editor + */ + mode: "manual" + } + }, + codeEditor: { + /** Select the text editor component used by the editor. + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired + */ + lib: "monaco", + options: { + /** The follow options only apply if the editor is set to "monaco" + * + * theme - must match the file name of a theme in + * packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/theme + * e.g. "tomorrow-night", "upstream-sunburst", "github", "my-theme" + */ + theme: "vs", + /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html + */ + //fontSize: 14, + //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", + //fontLigatures: true, + } + } + }, + +/******************************************************************************* + * Node Settings + * - fileWorkingDirectory + * - functionGlobalContext + * - functionExternalModules + * - nodeMessageBufferMaxLength + * - ui (for use with Node-RED Dashboard) + * - debugUseColors + * - debugMaxLength + * - execMaxBufferSize + * - httpRequestTimeout + * - mqttReconnectTime + * - serialReconnectTime + * - socketReconnectTime + * - socketTimeout + * - tcpMsgQueueSize + * - inboundWebSocketTimeout + * - tlsConfigDisableLocalFiles + * - webSocketNodeVerifyClient + ******************************************************************************/ + + /** The working directory to handle relative file paths from within the File nodes + * defaults to the working directory of the Node-RED process. + */ + //fileWorkingDirectory: "", + + /** Allow the Function node to load additional npm modules directly */ + functionExternalModules: true, + + /** The following property can be used to set predefined values in Global Context. + * This allows extra node modules to be made available with in Function node. + * For example, the following: + * functionGlobalContext: { os:require('os') } + * will allow the `os` module to be accessed in a Function node using: + * global.get("os") + */ +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, + /** The maximum number of messages nodes will buffer internally as part of their + * operation. This applies across a range of nodes that operate on message sequences. + * defaults to no limit. A value of 0 also means no limit is applied. + */ + //nodeMessageBufferMaxLength: 0, + + /** If you installed the optional node-red-dashboard you can set it's path + * relative to httpNodeRoot + * Other optional properties include + * readOnly:{boolean}, + * middleware:{function or array}, (req,res,next) - http middleware + * ioMiddleware:{function or array}, (socket,next) - socket.io middleware + */ + ui: { path: "" }, + + /** Colourise the console output of the debug node */ + //debugUseColors: true, + + /** The maximum length, in characters, of any message sent to the debug sidebar tab */ + debugMaxLength: 1000, + + /** Maximum buffer size for the exec node. Defaults to 10Mb */ + //execMaxBufferSize: 10000000, + + /** Timeout in milliseconds for HTTP request connections. Defaults to 120s */ + //httpRequestTimeout: 120000, + + /** Retry time in milliseconds for MQTT connections */ + mqttReconnectTime: 15000, + + /** Retry time in milliseconds for Serial port connections */ + serialReconnectTime: 15000, + + /** Retry time in milliseconds for TCP socket connections */ + //socketReconnectTime: 10000, + + /** Timeout in milliseconds for TCP server socket connections. Defaults to no timeout */ + //socketTimeout: 120000, + + /** Maximum number of messages to wait in queue while attempting to connect to TCP socket + * defaults to 1000 + */ + //tcpMsgQueueSize: 2000, + + /** Timeout in milliseconds for inbound WebSocket connections that do not + * match any configured node. Defaults to 5000 + */ + //inboundWebSocketTimeout: 5000, + + /** To disable the option for using local files for storing keys and + * certificates in the TLS configuration node, set this to true. + */ + //tlsConfigDisableLocalFiles: true, + + /** The following property can be used to verify websocket connection attempts. + * This allows, for example, the HTTP request headers to be checked to ensure + * they include valid authentication information. + */ + //webSocketNodeVerifyClient: function(info) { + // /** 'info' has three properties: + // * - origin : the value in the Origin header + // * - req : the HTTP request + // * - secure : true if req.connection.authorized or req.connection.encrypted is set + // * + // * The function should return true if the connection should be accepted, false otherwise. + // * + // * Alternatively, if this function is defined to accept a second argument, callback, + // * it can be used to verify the client asynchronously. + // * The callback takes three arguments: + // * - result : boolean, whether to accept the connection or not + // * - code : if result is false, the HTTP error status to return + // * - reason: if result is false, the HTTP reason string to return + // */ + //}, +} diff --git a/update/meanwhile/start.sh b/update/meanwhile/start.sh new file mode 100755 index 0000000..223ffae --- /dev/null +++ b/update/meanwhile/start.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +flow_dir="/home/pi/OpenScan/settings/.node-red" +flows_json_file=$flow_dir/flows.json +hostname=`hostname` +echo $hostname +session_token=`echo $RANDOM | md5sum | head -c 20` +echo $session_token > /home/pi/OpenScan/settings/session_token + +cat $flow_dir/flows.json.tmpl|sed "s|{{ hostname }}|$hostname.local|g" > $flows_json_file +sed -i "s|{{ session_token }}|$session_token|g" $flows_json_file diff --git a/update/mini/Arducam.py b/update/mini/Arducam.py deleted file mode 100644 index 941e07b..0000000 --- a/update/mini/Arducam.py +++ /dev/null @@ -1,202 +0,0 @@ -import time -import os - -try: - import v4l2 -except Exception as e: - print(e) - print("Try to install v4l2-fix") - try: - from pip import main as pipmain - except ImportError: - from pip._internal import main as pipmain - pipmain(['install', 'v4l2-fix']) - print("\nTry to run the focus program again.") - exit(0) - -import fcntl -import errno - -# # Type -# v4l2.V4L2_CTRL_TYPE_INTEGER -# v4l2.V4L2_CTRL_TYPE_BOOLEAN -# v4l2.V4L2_CTRL_TYPE_MENU -# v4l2.V4L2_CTRL_TYPE_BUTTON -# v4l2.V4L2_CTRL_TYPE_INTEGER64 -# v4l2.V4L2_CTRL_TYPE_CTRL_CLASS -# # Flags -# v4l2.V4L2_CTRL_FLAG_DISABLED -# v4l2.V4L2_CTRL_FLAG_GRABBED -# v4l2.V4L2_CTRL_FLAG_READ_ONLY -# v4l2.V4L2_CTRL_FLAG_UPDATE -# v4l2.V4L2_CTRL_FLAG_INACTIVE -# v4l2.V4L2_CTRL_FLAG_SLIDER - -def assert_valid_queryctrl(queryctrl): - return queryctrl.type & ( - v4l2.V4L2_CTRL_TYPE_INTEGER - | v4l2.V4L2_CTRL_TYPE_BOOLEAN - | v4l2.V4L2_CTRL_TYPE_MENU - | v4l2.V4L2_CTRL_TYPE_BUTTON - | v4l2.V4L2_CTRL_TYPE_INTEGER64 - | v4l2.V4L2_CTRL_TYPE_CTRL_CLASS - | 7 - | 8 - | 9 - ) and queryctrl.flags & ( - v4l2.V4L2_CTRL_FLAG_DISABLED - | v4l2.V4L2_CTRL_FLAG_GRABBED - | v4l2.V4L2_CTRL_FLAG_READ_ONLY - | v4l2.V4L2_CTRL_FLAG_UPDATE - | v4l2.V4L2_CTRL_FLAG_INACTIVE - | v4l2.V4L2_CTRL_FLAG_SLIDER - ) - -def get_device_controls_menu(fd, queryctrl): - querymenu = v4l2.v4l2_querymenu(queryctrl.id, queryctrl.minimum) - while querymenu.index <= queryctrl.maximum: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYMENU, querymenu) - yield querymenu - querymenu.index += 1 - -def get_device_controls_by_class(fd, control_class): - # enumeration by control class - queryctrl = v4l2.v4l2_queryctrl(control_class | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - while True: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - except IOError as e: - assert e.errno == errno.EINVAL - break - if v4l2.V4L2_CTRL_ID2CLASS(queryctrl.id) != control_class: - break - yield queryctrl - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id | v4l2.V4L2_CTRL_FLAG_NEXT_CTRL) - -def getdict(struct): - val = dict((field, getattr(struct, field)) for field, _ in struct._fields_) - val.pop("reserved") - return val - -def get_device_controls(fd): - # original enumeration method - queryctrl = v4l2.v4l2_queryctrl(v4l2.V4L2_CID_BASE) - while queryctrl.id < v4l2.V4L2_CID_LASTP1: - try: - fcntl.ioctl(fd, v4l2.VIDIOC_QUERYCTRL, queryctrl) - print(queryctrl.name) - except IOError as e: - # this predefined control is not supported by this device - assert e.errno == errno.EINVAL - queryctrl.id += 1 - continue - queryctrl = v4l2.v4l2_queryctrl(queryctrl.id + 1) - -def get_ctrls(vd): - ctrls = [] - # enumeration by control class - for class_ in (v4l2.V4L2_CTRL_CLASS_USER, v4l2.V4L2_CTRL_CLASS_MPEG, v4l2.V4L2_CTRL_CLASS_CAMERA): - for queryctrl in get_device_controls_by_class(vd, class_): - ctrl = getdict(queryctrl) - if queryctrl.type == v4l2.V4L2_CTRL_TYPE_MENU: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - # print(querymenu.name) - ctrl["menu"].append(querymenu.name) - - if queryctrl.type == 9: - ctrl["menu"] = [] - for querymenu in get_device_controls_menu(vd, queryctrl): - ctrl["menu"].append(querymenu.index) - ctrls.append(ctrl) - return ctrls - -def set_ctrl(vd, id, value): - ctrl = v4l2.v4l2_control() - ctrl.id = id - ctrl.value = value - try: - fcntl.ioctl(vd, v4l2.VIDIOC_S_CTRL, ctrl) - except IOError as e: - print(e) - -def get_ctrl(vd, id): - ctrl = v4l2.v4l2_control() - ctrl.id = id - try: - fcntl.ioctl(vd, v4l2.VIDIOC_G_CTRL, ctrl) - except IOError as e: - print(e) - return None - return ctrl.value - - -class Focuser: - FOCUS_ID = 0x009a090a - dev = None - - def __init__(self, dev=0): - self.focus_value = 0 - self.dev = dev - - if type(dev) == int or (type(dev) == str and dev.isnumeric()): - self.dev = "/dev/video{}".format(dev) - - self.fd = open(self.dev, 'r') - self.ctrls = get_ctrls(self.fd) - self.hasFocus = False - for ctrl in self.ctrls: - if ctrl['id'] == Focuser.FOCUS_ID: - self.hasFocus = True - self.opts[Focuser.OPT_FOCUS]["MIN_VALUE"] = ctrl['minimum'] - self.opts[Focuser.OPT_FOCUS]["MAX_VALUE"] = ctrl['maximum'] - self.opts[Focuser.OPT_FOCUS]["DEF_VALUE"] = ctrl['default'] - self.focus_value = get_ctrl(self.fd, Focuser.FOCUS_ID) - - if not self.hasFocus: - raise RuntimeError("Device {} has no focus_absolute control.".format(self.dev)) - - def read(self): - return self.focus_value - - def write(self, value): - self.focus_value = value - # os.system("v4l2-ctl -d {} -c focus_absolute={}".format(self.dev, value)) - set_ctrl(self.fd, Focuser.FOCUS_ID, value) - - OPT_BASE = 0x1000 - OPT_FOCUS = OPT_BASE | 0x01 - OPT_ZOOM = OPT_BASE | 0x02 - OPT_MOTOR_X = OPT_BASE | 0x03 - OPT_MOTOR_Y = OPT_BASE | 0x04 - OPT_IRCUT = OPT_BASE | 0x05 - opts = { - OPT_FOCUS : { - "MIN_VALUE": 0, - "MAX_VALUE": 1000, - "DEF_VALUE": 0, - }, - } - def reset(self,opt,flag = 1): - info = self.opts[opt] - if info == None or info["DEF_VALUE"] == None: - return - self.set(opt,info["DEF_VALUE"]) - - def get(self,opt,flag = 0): - info = self.opts[opt] - return self.read() - - def set(self,opt,value,flag = 1): - info = self.opts[opt] - if value > info["MAX_VALUE"]: - value = info["MAX_VALUE"] - elif value < info["MIN_VALUE"]: - value = info["MIN_VALUE"] - self.write(value) - print("write: {}".format(value)) - - def __del__(self): - self.fd.close() - -pass diff --git a/update/mini/fla.py b/update/mini/fla.py deleted file mode 100644 index 8c6ab3d..0000000 --- a/update/mini/fla.py +++ /dev/null @@ -1,100 +0,0 @@ -from flask import Flask, make_response, jsonify, request, abort -from PIL import Image -import gphoto2 as gp -from time import sleep -import shutil -from OpenScan import load_int, load_float, load_bool -import RPi.GPIO as GPIO - -GPIO.setwarnings(False) -GPIO.setmode(GPIO.BCM) - -app = Flask(__name__) - -basedir = '/home/pi/OpenScan/' - -################################################################################################################### -@app.route('/gphoto_init', methods=['get']) -def gphoto_init(): - global camera - camera = gp.Camera() - camera.init() - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_preview', methods=['get']) -def gphoto_preview(): - filepath = str(request.args.get('filepath')) - camera_file = gp.gp_camera_capture_preview(camera)[1] - target = basedir + filepath - camera_file.save(target) - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_capture', methods=['get']) -def gphoto_capture(): - filepath = str(request.args.get('filepath')) - file_path = camera.capture(gp.GP_CAPTURE_IMAGE) - camera_file = camera.file_get(file_path.folder, file_path.name, gp.GP_FILE_TYPE_NORMAL) - camera_file.save(basedir + filepath) - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_test', methods=['get']) -def gphoto_test(): - text = camera.get_summary() - return ({}, 200) -################################################################################################################### -@app.route('/gphoto_exit', methods=['get']) -def gphoto_exit(): - global camera - camera.exit() - return ({}, 200) -################################################################################################################### -@app.route('/crop', methods=['get']) -def crop(): - downscale_threshold = 1000 - filepath_in = basedir + str(request.args.get('filepath_in')) - filepath_out = basedir + str(request.args.get('filepath_out')) - cropx = int(request.args.get('cropx'))/200 - cropy = int(request.args.get('cropy'))/200 - rotation = int(request.args.get('rotation')) - preview = str(request.args.get('preview')) - - with Image.open(filepath_in) as img: - w,h = img.size - if cropx != 0 or cropy != 0: - img = img.crop((w*cropx, h*cropy, w * (1-cropx), h * (1-cropy))) - if rotation == 90: - img = img.transpose(Image.ROTATE_90) - elif rotation == 180: - img= img.transpose(Image.ROTATE_180) - elif rotation == 270: - img= img.transpose(Image.ROTATE_270) - if preview == "True": - w,h = img.size - if w > downscale_threshold or h > downscale_threshold: - downscale = max(w/downscale_threshold,h/downscale_threshold) - img = img.resize((int(w/downscale),int(h/downscale)),Image.ANTIALIAS) - img.save(filepath_out, quality=95, subsampling=0) - return ({}, 200) - -################################################################################################################### -@app.route('/external_capture', methods=['get']) -def external_capture(): - pin = load_int('pin_external') - delay_before = load_float('cam_delay_before') - timeout = load_float('cam_timeout')/1000 - delay_after = load_float('cam_delay_after') - GPIO.setup(pin, GPIO.OUT) - GPIO.output(pin, GPIO.LOW) - sleep(delay_before) - GPIO.output(pin, GPIO.HIGH) - sleep(timeout) - GPIO.output(pin, GPIO.LOW) - sleep(delay_after) - return ({}, 200) - - - - -if __name__ == '__main__': - app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) -# app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) diff --git a/update/mini/flows.json b/update/mini/flows.json deleted file mode 100644 index 83c64c0..0000000 --- a/update/mini/flows.json +++ /dev/null @@ -1,5500 +0,0 @@ -[ - { - "id": "829d803b6033a693", - "type": "tab", - "label": "HOME", - "disabled": false, - "info": "", - "env": [] - }, - { - "id": "1613373abaf77a2c", - "type": "tab", - "label": "SCAN", - "disabled": false, - "info": "", - "env": [] - }, - { - "id": "4981d84ef1a366d1", - "type": "tab", - "label": "Files&Cloud", - "disabled": false, - "info": "", - "env": [] - }, - { - "id": "017bd4e4a428bee5", - "type": "tab", - "label": "SETTINGS", - "disabled": false, - "info": "", - "env": [] - }, - { - "id": "b3150b13e34b1fe8", - "type": "ui_tab", - "name": "OpenScan", - "icon": "dashboard", - "order": 1, - "disabled": false, - "hidden": false - }, - { - "id": "b6e9c2df6b28ff66", - "type": "ui_base", - "theme": { - "name": "theme-dark", - "lightTheme": { - "default": "#0094CE", - "baseColor": "#0094CE", - "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", - "edited": true, - "reset": false - }, - "darkTheme": { - "default": "#097479", - "baseColor": "#097479", - "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", - "edited": true, - "reset": false - }, - "customTheme": { - "name": "Untitled Theme 1", - "default": "#4B7930", - "baseColor": "#4B7930", - "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" - }, - "themeState": { - "base-color": { - "default": "#097479", - "value": "#097479", - "edited": false - }, - "page-titlebar-backgroundColor": { - "value": "#097479", - "edited": false - }, - "page-backgroundColor": { - "value": "#111111", - "edited": false - }, - "page-sidebar-backgroundColor": { - "value": "#333333", - "edited": false - }, - "group-textColor": { - "value": "#0eb8c0", - "edited": false - }, - "group-borderColor": { - "value": "#555555", - "edited": false - }, - "group-backgroundColor": { - "value": "#333333", - "edited": false - }, - "widget-textColor": { - "value": "#eeeeee", - "edited": false - }, - "widget-backgroundColor": { - "value": "#097479", - "edited": false - }, - "widget-borderColor": { - "value": "#333333", - "edited": false - }, - "base-font": { - "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" - } - }, - "angularTheme": { - "primary": "indigo", - "accents": "blue", - "warn": "red", - "background": "grey", - "palette": "light" - } - }, - "site": { - "name": "OpenScan 3D Scanner", - "hideToolbar": "false", - "allowSwipe": "false", - "lockMenu": "false", - "allowTempTheme": "true", - "dateFormat": "DD/MM/YYYY", - "sizes": { - "sx": 46, - "sy": 46, - "gx": 10, - "gy": 10, - "cx": 6, - "cy": 6, - "px": 6, - "py": 6 - } - } - }, - { - "id": "729f9ea6e3513c9b", - "type": "ui_group", - "name": "Home", - "tab": "b3150b13e34b1fe8", - "order": 1, - "disp": false, - "width": "6", - "collapse": false, - "className": "" - }, - { - "id": "65ae49b64fa0d83e", - "type": "ui_tab", - "name": "Settings", - "icon": "dashboard", - "order": 4, - "disabled": false, - "hidden": false - }, - { - "id": "e23b837a9f040895", - "type": "ui_tab", - "name": "Scan", - "icon": "dashboard", - "order": 2, - "disabled": false, - "hidden": false - }, - { - "id": "7aaf184330605300", - "type": "ui_group", - "name": "Settings", - "tab": "e23b837a9f040895", - "order": 1, - "disp": false, - "width": "6", - "collapse": false, - "className": "" - }, - { - "id": "90223f7ddc082321", - "type": "ui_group", - "name": "Arducam", - "tab": "e23b837a9f040895", - "order": 3, - "disp": false, - "width": 10, - "collapse": false, - "className": "" - }, - { - "id": "7625f9c9e8dbc5c6", - "type": "ui_spacer", - "z": "017bd4e4a428bee5", - "name": "spacer", - "group": "", - "order": 4, - "width": 1, - "height": 1 - }, - { - "id": "3b4bd36726be16d5", - "type": "ui_group", - "name": "Settings", - "tab": "65ae49b64fa0d83e", - "order": 3, - "disp": false, - "width": "6", - "collapse": false, - "className": "" - }, - { - "id": "b5fdd57b.15eda8", - "type": "ui_group", - "name": "Main", - "tab": "15a222ed.d70a7d", - "order": 1, - "disp": false, - "width": 13, - "collapse": false - }, - { - "id": "db43d646.2074c8", - "type": "ui_group", - "name": "OpenScanCloud", - "tab": "15a222ed.d70a7d", - "order": 2, - "disp": false, - "width": "6", - "collapse": false, - "className": "" - }, - { - "id": "15a222ed.d70a7d", - "type": "ui_tab", - "name": "Files&Cloud", - "icon": "dashboard", - "order": 3, - "disabled": false, - "hidden": false - }, - { - "id": "d9b28c5fbfd37509", - "type": "ui_spacer", - "z": "1613373abaf77a2c", - "name": "spacer", - "group": "7aaf184330605300", - "order": 21, - "width": 1, - "height": 1 - }, - { - "id": "cc7d61f1cfd44578", - "type": "ui_spacer", - "z": "1613373abaf77a2c", - "name": "spacer", - "group": "7aaf184330605300", - "order": 24, - "width": 1, - "height": 1 - }, - { - "id": "bba223eda03b67eb", - "type": "ui_spacer", - "z": "1613373abaf77a2c", - "name": "spacer", - "group": "7aaf184330605300", - "order": 25, - "width": 1, - "height": 1 - }, - { - "id": "e28012f571abd8dc", - "type": "ui_spacer", - "z": "1613373abaf77a2c", - "name": "spacer", - "group": "7aaf184330605300", - "order": 28, - "width": 1, - "height": 1 - }, - { - "id": "b32d71fea63612b7", - "type": "ui_spacer", - "z": "1613373abaf77a2c", - "name": "spacer", - "group": "90223f7ddc082321", - "order": 1, - "width": 2, - "height": 1 - }, - { - "id": "4cf8566a9121fe3f", - "type": "ui_spacer", - "z": "1613373abaf77a2c", - "name": "spacer", - "group": "90223f7ddc082321", - "order": 7, - "width": 2, - "height": 1 - }, - { - "id": "2cc829a5.610f36", - "type": "ui_group", - "name": "group-test", - "tab": "", - "order": 3, - "disp": false, - "width": 3, - "collapse": false - }, - { - "id": "65285822f24120f4", - "type": "ui_spacer", - "z": "017bd4e4a428bee5", - "name": "spacer", - "group": "3b4bd36726be16d5", - "order": 8, - "width": 6, - "height": 1 - }, - { - "id": "90d444dfdfccf138", - "type": "ui_spacer", - "z": "017bd4e4a428bee5", - "name": "spacer", - "group": "3b4bd36726be16d5", - "order": 15, - "width": 6, - "height": 1 - }, - { - "id": "c9dbf6219837d6d7", - "type": "ui_spacer", - "z": "017bd4e4a428bee5", - "name": "spacer", - "group": "3b4bd36726be16d5", - "order": 22, - "width": 6, - "height": 1 - }, - { - "id": "3fe52603e2ac73b6", - "type": "ui_template", - "z": "829d803b6033a693", - "group": "729f9ea6e3513c9b", - "name": "Background", - "order": 1, - "width": 0, - "height": 0, - "format": "", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": false, - "templateScope": "global", - "className": "", - "x": 110, - "y": 40, - "wires": [ - [] - ] - }, - { - "id": "4468f691.103eb8", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 2, - "width": 2, - "height": 2, - "passthru": false, - "label": "SCAN", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "1", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 100, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] - }, - { - "id": "6560dd25.9e76c4", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 4, - "width": 2, - "height": 2, - "passthru": false, - "label": "Settings", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "3", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 100, - "y": 180, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] - }, - { - "id": "62cd5288.2805fc", - "type": "ui_ui_control", - "z": "829d803b6033a693", - "name": "", - "events": "all", - "x": 300, - "y": 100, - "wires": [ - [] - ] - }, - { - "id": "71e72293.91c6fc", - "type": "ui_button", - "z": "829d803b6033a693", - "name": "", - "group": "729f9ea6e3513c9b", - "order": 3, - "width": 2, - "height": 2, - "passthru": false, - "label": "Files", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "2", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 140, - "wires": [ - [ - "62cd5288.2805fc" - ] - ] - }, - { - "id": "88edad7ca53698fd", - "type": "inject", - "z": "829d803b6033a693", - "name": "1s", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": true, - "onceDelay": "1", - "topic": "", - "payload": "true", - "payloadType": "bool", - "x": 90, - "y": 320, - "wires": [ - [ - "000a811a215e08d4", - "83c2b5ea51f0fec3", - "88fde4ab78c965d7", - "bee62d2a99cbc63b", - "4fa53fb9738cb1d3" - ] - ] - }, - { - "id": "bd75f33b8a57c522", - "type": "link out", - "z": "829d803b6033a693", - "name": "enable", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "92c98e6ce7cd25f9" - ], - "x": 335, - "y": 360, - "wires": [] - }, - { - "id": "000a811a215e08d4", - "type": "function", - "z": "829d803b6033a693", - "name": "enable", - "func": "msg.enabled = true\nmsg.payload = 1\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 230, - "y": 360, - "wires": [ - [ - "bd75f33b8a57c522" - ] - ] - }, - { - "id": "83c2b5ea51f0fec3", - "type": "function", - "z": "829d803b6033a693", - "name": "disable", - "func": "msg.enabled = false\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 240, - "y": 400, - "wires": [ - [ - "6b94bf2295b1b31d" - ] - ] - }, - { - "id": "6b94bf2295b1b31d", - "type": "link out", - "z": "829d803b6033a693", - "name": "disable", - "mode": "link", - "links": [ - "a1d29e56599da0bd" - ], - "x": 335, - "y": 400, - "wires": [] - }, - { - "id": "88fde4ab78c965d7", - "type": "function", - "z": "829d803b6033a693", - "name": "write", - "func": "var file = 'status_cloud'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\ncontent = 'ready'\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 230, - "y": 440, - "wires": [ - [] - ] - }, - { - "id": "960912e90ba5b5bc", - "type": "link out", - "z": "829d803b6033a693", - "name": "started1s", - "mode": "link", - "links": [ - "2f4c0f98.dee2", - "397ab7f44b893c89", - "65145c939b6647e2", - "65b38bfeb3fee710", - "6d1e12f51f9af0b6", - "788fabff98c7973c", - "9b2bc9849aee310b", - "a1e14624058e74cd", - "a67c18aaca2f5fa5", - "bd80ec228fb9a86d", - "cc9c4092edeb43cc", - "d3fc91d87d5d5f62", - "d7c1fb4c028b21a5", - "e5f38b4a07a5e278", - "f0b355967b33dfee", - "d0104e0163745993", - "5e7d5e4335d37794", - "e0965e490d53617f", - "612a7556ab11cf7d", - "482bc06e02eec5b9" - ], - "x": 615, - "y": 720, - "wires": [] - }, - { - "id": "168d72a54504b327", - "type": "inject", - "z": "829d803b6033a693", - "name": "5/0.1s", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "0.1", - "crontab": "", - "once": true, - "onceDelay": "5", - "topic": "", - "payload": "", - "payloadType": "str", - "x": 100, - "y": 620, - "wires": [ - [ - "6c6ef2255a7d39e5" - ] - ] - }, - { - "id": "6c6ef2255a7d39e5", - "type": "link out", - "z": "829d803b6033a693", - "name": "repeat 5s/0.1s", - "mode": "link", - "links": [ - "61990987acd0f263", - "2415272f42ce468c" - ], - "x": 195, - "y": 640, - "wires": [] - }, - { - "id": "bee62d2a99cbc63b", - "type": "function", - "z": "829d803b6033a693", - "name": "global", - "func": "global.set('flag_pw', true)\nglobal.set('flag', true)\nglobal.set('combine', false)\nglobal.set('focus', 2838)\nglobal.set('focus1', 0)\nglobal.set('focus2', 0)\n\nglobal.set('focuser', true)\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 230, - "y": 320, - "wires": [ - [] - ] - }, - { - "id": "544d20f02215011a", - "type": "function", - "z": "829d803b6033a693", - "name": "CREATE FACTORY DEFAULT", - "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cameras':{\n 'imx519':[4656,3496],\n 'imx219':[3280,2464],\n 'imx477':[4056,3040],\n 'ov5647':[2592,1944],\n 'imx378':[3840,2880],\n 'ov9271':[1280,800],\n 'imx290a':[1920,1080],\n 'imx290b':[1920,1080],\n },\n 'cam_AFmode':true,\n 'cam_STmode':true,\n 'cam_stacksize':2,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':0,\n 'cam_saturation':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'hostname':'',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n 'pin_endstop1':24,\n 'pin_endstop2':25,\n 'pin_external':10,\n 'pin_ringlight1':17,\n 'pin_ringlight2':27,\n 'pin_rotor_dir':5,\n 'pin_rotor_enable':23,\n 'pin_rotor_step':6,\n 'pin_tt_dir':9,\n 'pin_tt_enable':22,\n 'pin_tt_step':11,\n 'rotor_acc':1,\n 'rotor_accramp':2000,\n 'rotor_angle':10,\n 'rotor_anglemax':60,\n 'rotor_anglemin':-40,\n 'rotor_anglestart':0,\n 'rotor_delay':0.0001,\n 'rotor_dir':1,\n 'rotor_stepsperrotation':48000,\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n 'tt_acc':1,\n 'tt_accramp':200,\n 'tt_angle':10,\n 'tt_delay':0.0001,\n 'tt_dir':1,\n 'tt_stepsperrotation':3200,\n 'cam_focus':2838,\n 'cam_focus1':0,\n 'cam_focus2':0,\n 'uploadprogress':'',\n 'update_type':'main',\n 'update_auto':true,\n 'turntable_mode':true,\n}}\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 310, - "y": 720, - "wires": [ - [ - "c77552216a8bb781" - ] - ] - }, - { - "id": "a1f0ed7d5a9d670e", - "type": "inject", - "z": "829d803b6033a693", - "name": "", - "props": [ - { - "p": "overwrite", - "v": "false", - "vt": "bool" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": true, - "onceDelay": "0.1", - "topic": "", - "x": 90, - "y": 720, - "wires": [ - [ - "544d20f02215011a" - ] - ] - }, - { - "id": "c77552216a8bb781", - "type": "python3-function", - "z": "829d803b6033a693", - "name": "chk files", - "func": "from os import listdir\n\nbasedir = '/home/pi/OpenScan/settings/'\n\nmsg['payload'] = ''\n\nfiles = listdir(basedir)\n\nfor i in msg['settings']:\n if msg['overwrite'] != True:\n if i not in files:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n else:\n with open(basedir + i, 'w+') as file:\n file.write(str(msg['settings'][i])) \n\nmsg['payload'] = True\n\nreturn msg", - "outputs": 1, - "x": 520, - "y": 720, - "wires": [ - [ - "960912e90ba5b5bc" - ] - ] - }, - { - "id": "38783aea9cc317a6", - "type": "link in", - "z": "829d803b6033a693", - "name": "factory reset", - "links": [ - "80bccc884b0be297" - ], - "x": 135, - "y": 760, - "wires": [ - [ - "544d20f02215011a" - ] - ] - }, - { - "id": "4fa53fb9738cb1d3", - "type": "python3-function", - "z": "829d803b6033a693", - "name": "create log", - "func": "import subprocess\n\n\nlog = '############################################DMESG############################################\\n'\nlog += subprocess.getoutput(\"dmesg\")\nlog += '\\n############################################SYSLOG############################################\\n'\nlog += subprocess.getoutput(\"tail -10000 /var/log/syslog\")\n\nwith open('/home/pi/OpenScan/tmp/log.txt', 'w+') as file:\n file.write(log)\n\nreturn msg", - "outputs": 1, - "x": 240, - "y": 480, - "wires": [ - [] - ] - }, - { - "id": "828e5298.d2192", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 9, - "width": 2, - "height": 1, - "passthru": false, - "label": "⇐", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 400, - "wires": [ - [ - "b12e54fb.3141b8" - ] - ] - }, - { - "id": "96c7e241.458e6", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 10, - "width": 2, - "height": 1, - "passthru": false, - "label": "⇒", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 440, - "wires": [ - [ - "37f52dd4.bd7572" - ] - ] - }, - { - "id": "2e854876.6b6008", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 6, - "width": 2, - "height": 1, - "passthru": true, - "label": "⇑", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 280, - "wires": [ - [ - "555aea34.b3b5e4" - ] - ] - }, - { - "id": "753817f.1b9b3e8", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "", - "group": "7aaf184330605300", - "order": 7, - "width": 2, - "height": 1, - "passthru": true, - "label": "⇓", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "num", - "topic": "", - "topicType": "str", - "x": 90, - "y": 320, - "wires": [ - [ - "9905e0c9.dddcd" - ] - ] - }, - { - "id": "8775044.3aa3ef8", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 8, - "width": 2, - "height": 1, - "name": "", - "label": "Turntable", - "format": "", - "layout": "row-left", - "className": "", - "x": 100, - "y": 360, - "wires": [] - }, - { - "id": "9e8a2d23.bf6ce", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 5, - "width": 2, - "height": 1, - "name": "", - "label": "Rotor", - "format": "", - "layout": "row-left", - "className": "", - "x": 90, - "y": 240, - "wires": [] - }, - { - "id": "555aea34.b3b5e4", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 280, - "wires": [ - [ - "46e00b45.c24ca4" - ] - ] - }, - { - "id": "9905e0c9.dddcd", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 320, - "wires": [ - [ - "6ee089cb343a35ef" - ] - ] - }, - { - "id": "b12e54fb.3141b8", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 400, - "wires": [ - [ - "c1871a2b9af5419a" - ] - ] - }, - { - "id": "37f52dd4.bd7572", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "lmt 0.2/s", - "pauseType": "rate", - "timeout": "0.1", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "0.2", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": true, - "outputs": 1, - "x": 220, - "y": 440, - "wires": [ - [ - "42b9f1fc49e69f54" - ] - ] - }, - { - "id": "46e00b45.c24ca4", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Rotor left", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('rotor',load_int('rotor_angle'))", - "outputs": 1, - "x": 360, - "y": 280, - "wires": [ - [] - ] - }, - { - "id": "6ee089cb343a35ef", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Rotor right", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('rotor',-load_int('rotor_angle'))", - "outputs": 1, - "x": 370, - "y": 320, - "wires": [ - [] - ] - }, - { - "id": "42b9f1fc49e69f54", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "TT right", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('tt',-load_int('tt_angle'))", - "outputs": 1, - "x": 360, - "y": 440, - "wires": [ - [] - ] - }, - { - "id": "c1871a2b9af5419a", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "TT left", - "func": "from OpenScan import motorrun, load_int\n\nmotorrun('tt',load_int('tt_angle'))", - "outputs": 1, - "x": 350, - "y": 400, - "wires": [ - [] - ] - }, - { - "id": "aebad788761dce4a", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "routine_photocount", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 14, - "width": 3, - "height": 1, - "passthru": true, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "10", - "max": "300", - "step": "10", - "className": "", - "x": 350, - "y": 540, - "wires": [ - [ - "ce28a0b5bfb0d5a1" - ] - ] - }, - { - "id": "107a030938cbfea9", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 540, - "wires": [ - [ - "aebad788761dce4a" - ] - ] - }, - { - "id": "ce28a0b5bfb0d5a1", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'routine_photocount'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 540, - "wires": [ - [] - ] - }, - { - "id": "84d6b96c8ebaac96", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadF", - "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseFloat(data) / 1000;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 580, - "wires": [ - [ - "470b10726d298834" - ] - ] - }, - { - "id": "470b10726d298834", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "shutter ", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 16, - "width": 3, - "height": 1, - "passthru": true, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "1", - "max": "300", - "step": "1", - "className": "", - "x": 310, - "y": 580, - "wires": [ - [ - "44c3947a9b92d32d" - ] - ] - }, - { - "id": "44c3947a9b92d32d", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_shutter'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload * 1000)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 580, - "wires": [ - [] - ] - }, - { - "id": "069bcf58b1fe44cd", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 13, - "width": 3, - "height": 1, - "name": "photocount", - "label": "Photos", - "format": "", - "layout": "row-left", - "className": "", - "x": 670, - "y": 540, - "wires": [] - }, - { - "id": "8dc7df1de59cb03a", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 15, - "width": 3, - "height": 1, - "name": "shutter", - "label": "Shutter (ms)", - "format": "", - "layout": "row-left", - "className": "", - "x": 650, - "y": 580, - "wires": [] - }, - { - "id": "cc69dba8d54a29dd", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "Crop X", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 18, - "width": 3, - "height": 1, - "passthru": true, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0", - "max": "99", - "step": "1", - "className": "", - "x": 320, - "y": 620, - "wires": [ - [ - "c2b2ab5524271123" - ] - ] - }, - { - "id": "e3a90602605fb9e9", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "Crop Y", - "label": " ", - "tooltip": "", - "group": "7aaf184330605300", - "order": 20, - "width": 3, - "height": 1, - "passthru": true, - "outs": "end", - "topic": "", - "topicType": "str", - "min": "0", - "max": "99", - "step": "1", - "className": "", - "x": 310, - "y": 660, - "wires": [ - [ - "26f17a7f406df73c" - ] - ] - }, - { - "id": "9c6b48b7b4cc4e1a", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 620, - "wires": [ - [ - "cc69dba8d54a29dd" - ] - ] - }, - { - "id": "c470fd0b15356206", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 660, - "wires": [ - [ - "e3a90602605fb9e9" - ] - ] - }, - { - "id": "c2b2ab5524271123", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_cropx'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 620, - "wires": [ - [] - ] - }, - { - "id": "26f17a7f406df73c", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'cam_cropy'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 660, - "wires": [ - [] - ] - }, - { - "id": "fecf5cff888bb570", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 17, - "width": 3, - "height": 1, - "name": "cropx", - "label": "Crop X (%)", - "format": "", - "layout": "row-left", - "className": "", - "x": 650, - "y": 620, - "wires": [] - }, - { - "id": "0ee4950bd21498bd", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 19, - "width": 3, - "height": 1, - "name": "cropy", - "label": "Crop Y (%)", - "format": "", - "layout": "row-left", - "className": "", - "x": 650, - "y": 660, - "wires": [] - }, - { - "id": "ebbf11b55d758806", - "type": "ui_text_input", - "z": "1613373abaf77a2c", - "name": "", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 4, - "width": 3, - "height": 1, - "passthru": true, - "mode": "text", - "delay": "0", - "topic": "", - "sendOnBlur": true, - "className": "", - "topicType": "str", - "x": 320, - "y": 500, - "wires": [ - [ - "67385b196c517ac6" - ] - ] - }, - { - "id": "f4b3112a9ec6c487", - "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.payload=\"default\"\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 500, - "wires": [ - [ - "ebbf11b55d758806" - ] - ] - }, - { - "id": "67385b196c517ac6", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'routine_projectname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload).replace(/ /g, '_')\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 510, - "y": 500, - "wires": [ - [] - ] - }, - { - "id": "4dd7285c2b0fd79b", - "type": "ui_slider", - "z": "1613373abaf77a2c", - "name": "ringlight", - "label": "", - "tooltip": "", - "group": "7aaf184330605300", - "order": 12, - "width": 3, - "height": 1, - "passthru": true, - "outs": "all", - "topic": "", - "topicType": "str", - "min": 0, - "max": "3", - "step": 1, - "className": "", - "x": 320, - "y": 700, - "wires": [ - [ - "873dace18a23fdf2" - ] - ] - }, - { - "id": "873dace18a23fdf2", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "LED", - "func": "from OpenScan import ringlight\nval = msg['payload']\n\nif val == 0:\n ringlight(1,False)\n ringlight(2,False)\nelif val == 1:\n ringlight(1,True)\n ringlight(2,False)\nelif val == 2:\n ringlight(1,False)\n ringlight(2,True)\nelif val == 3:\n ringlight(1,True)\n ringlight(2,True)\n", - "outputs": 1, - "x": 510, - "y": 700, - "wires": [ - [] - ] - }, - { - "id": "9e30e33a1520fee0", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadI", - "func": "msg.payload = 0\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 190, - "y": 700, - "wires": [ - [ - "4dd7285c2b0fd79b" - ] - ] - }, - { - "id": "7dd287f40385922f", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "start ", - "group": "7aaf184330605300", - "order": 22, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-play", - "payload": "", - "payloadType": "date", - "topic": "enabled", - "topicType": "str", - "x": 150, - "y": 880, - "wires": [ - [ - "431f917c2541ae48", - "33d94a04b96a2de0", - "6d15f717d5a11002" - ] - ] - }, - { - "id": "579f2211199fd6ab", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "stop", - "group": "7aaf184330605300", - "order": 23, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-stop", - "payload": "numberofphotos", - "payloadType": "global", - "topic": "", - "topicType": "str", - "x": 750, - "y": 920, - "wires": [ - [ - "1787f08ed7070ddd", - "c1c044f3c2139f68" - ] - ] - }, - { - "id": "431f917c2541ae48", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Routine", - "func": "from OpenScan import load_str, load_int, motorrun, create_coordinates, take_photo, save, load_bool, camera\nfrom time import sleep, strftime\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system\nfrom os.path import isfile\nfrom Arducam import Focuser\n\nstatus = load_str(\"status_internal_cam\")\n\nif status == \"no camera found\":\n return\n\nif not status == \"Routine-stopping\":\n save('status_internal_cam','Routine-preparing')\n\nprojectname=load_str(\"routine_projectname\")\nphotocount = load_int('routine_photocount') #vorher point_count\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nangle_start = load_int('rotor_anglestart')\n\ncounter = 0\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp/tmp.jpg'\nzippath = basepath + 'tmp/tmp.zip'\n\nif not 'projectcode' in msg:\n projectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n msg['projectcode'] = projectcode\n msg['counter'] = -1\n if isfile(zippath):\n system('rm ' + zippath)\n sleep(1)\n\nprojectcode = msg['projectcode']\nmsg['counter'] += 1\n\ntt_mode = load_bool('turntable_mode')\n\nif tt_mode == False:\n coordinates = create_coordinates(angle_min,angle_max,photocount)\nelse:\n angle_start = 0\n coordinates = []\n for i in range (photocount):\n coordinates.append([0,360/photocount*(i+1)])\n\nposition_last = (angle_start , 0)\n\nzip = ZipFile(zippath, \"a\",ZIP_DEFLATED, allowZip64=True)\n\nfor position in coordinates:\n counter += 1\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n\n\n rotor_angle = position_last[0] - position[0]\n if abs(rotor_angle) > 180:\n rotor_angle = -360 * rotor_angle/abs(rotor_angle) + rotor_angle\n\n tt_angle = position_last[1] - position[1]\n #if abs(tt_angle) > 180:\n # tt_angle = -360 * tt_angle/abs(tt_angle) + tt_angle\n \n motorrun('rotor', rotor_angle)\n motorrun('tt', tt_angle)\n\n\n\n msg['cropx'] = load_int('cam_cropx')\n msg['cropy'] = load_int('cam_cropy')\n msg['rotation'] = load_int('cam_rotation')\n msg['filepath_in'] = 'tmp/tmp.jpg'\n msg['filepath_out'] = 'tmp/tmp.jpg'\n msg['filepath'] = 'tmp/tmp.jpg'\n if load_str('status_internal_cam') != \"Routine-stopping\":\n save('status_internal_cam','Routine-Photo ' + str(counter) + '/' + str(photocount))\n take_photo('tmp/tmp.jpg')\n camera('/crop',msg)\n\n\n \n zip.write(temppath, projectname + '_' + str(counter + msg['counter']*photocount) + \".jpg\")\n system('cp ' + temppath + ' ' + basepath +'tmp/preview.jpg')\n\n position_last = position\n\n\nzip.close()\n\n\nsave('status_internal_cam','Routine-done')\n\nmotorrun('rotor',position_last[0] - angle_start)\nmotorrun('tt',position_last[1])\n\nsave('status_internal_cam','--READY--')\n\nmsg['topic'] = 'Scan done'\nmsg['payload'] = 'Do you want to continue scanning or finish this project?'\nmsg['enabled'] = False\nreturn msg\n\n", - "outputs": 1, - "x": 300, - "y": 840, - "wires": [ - [ - "db7eea74d3bf892b" - ] - ] - }, - { - "id": "1787f08ed7070ddd", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "stop", - "func": "from OpenScan import load_str, save\n\nstatus = load_str('status_internal_cam')\n\nif status == 'no camera found' or status[:5]=='Featu' or status =='--READY--':\n return\n\nsave('status_internal_cam', 'Routine-stopping')", - "outputs": 1, - "x": 930, - "y": 920, - "wires": [ - [] - ] - }, - { - "id": "e9b13dfd9f8d3711", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "b33d604c.5f1a6" - ], - "x": 395, - "y": 800, - "wires": [] - }, - { - "id": "5ba05110851a5096", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "reboot", - "group": "7aaf184330605300", - "order": 26, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "reboot", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-repeat", - "payload": "", - "payloadType": "date", - "topic": "", - "topicType": "str", - "x": 90, - "y": 1000, - "wires": [ - [ - "16c76929f88df841" - ] - ] - }, - { - "id": "152d402caa595189", - "type": "ui_button", - "z": "1613373abaf77a2c", - "name": "shutdown", - "group": "7aaf184330605300", - "order": 27, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "shutdown", - "color": "", - "bgcolor": "", - "className": "", - "icon": "fa-power-off", - "payload": "", - "payloadType": "date", - "topic": "", - "topicType": "str", - "x": 100, - "y": 1040, - "wires": [ - [ - "597bfb653e8cddbf" - ] - ] - }, - { - "id": "16c76929f88df841", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", - "links": [ - "9bb0adbd716ce347" - ], - "x": 215, - "y": 1000, - "wires": [] - }, - { - "id": "597bfb653e8cddbf", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", - "links": [ - "fc9abb94c35eec56" - ], - "x": 215, - "y": 1040, - "wires": [] - }, - { - "id": "9654deebb668e012", - "type": "inject", - "z": "1613373abaf77a2c", - "name": "1s", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": true, - "onceDelay": "1", - "topic": "", - "payload": "", - "payloadType": "date", - "x": 110, - "y": 960, - "wires": [ - [ - "c1c044f3c2139f68" - ] - ] - }, - { - "id": "8367cfa0bf5bc5df", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "start routine", - "links": [ - "210ef5246d1a8790", - "84608db962fd9932", - "8689e938.dd9e38", - "f20f2dbc.0f123", - "e9b13dfd9f8d3711", - "96bdb9417e38810f", - "fb13752beddee9f2", - "bd75f33b8a57c522" - ], - "x": 55, - "y": 880, - "wires": [ - [ - "7dd287f40385922f" - ] - ] - }, - { - "id": "fb13752beddee9f2", - "type": "link out", - "z": "1613373abaf77a2c", - "name": "", - "mode": "link", - "links": [ - "2f4c0f98.dee2", - "8367cfa0bf5bc5df", - "b33d604c.5f1a6", - "482bc06e02eec5b9" - ], - "x": 865, - "y": 880, - "wires": [] - }, - { - "id": "95439678bb2df2a2", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "msg.flag = global.get('flag')\nif (global.get('flag_pw')== true){\n return msg\n}\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 1160, - "wires": [ - [ - "04cc2467807d2d6b", - "14f9617b5b301318" - ] - ] - }, - { - "id": "948a3ae4444685f2", - "type": "change", - "z": "1613373abaf77a2c", - "name": "flag_pw true", - "rules": [ - { - "t": "set", - "p": "flag_pw", - "pt": "global", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 650, - "y": 1200, - "wires": [ - [] - ] - }, - { - "id": "04cc2467807d2d6b", - "type": "change", - "z": "1613373abaf77a2c", - "name": "flag_pw false", - "rules": [ - { - "t": "set", - "p": "flag_pw", - "pt": "global", - "to": "false", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 430, - "y": 1200, - "wires": [ - [] - ] - }, - { - "id": "12f1399b240830bf", - "type": "exec", - "z": "1613373abaf77a2c", - "command": " v4l2-ctl --list-formats-ext", - "addpay": "", - "append": "", - "useSpawn": "true", - "timer": "", - "winHide": false, - "oldrc": false, - "name": "check cam", - "x": 190, - "y": 100, - "wires": [ - [ - "6222f781629c72e7" - ], - [ - "6222f781629c72e7" - ], - [] - ] - }, - { - "id": "6222f781629c72e7", - "type": "function", - "z": "1613373abaf77a2c", - "name": "write", - "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\ncontent = '--READY--'\n\nif (msg.payload.includes('Cannot open device')){\n content = 'no camera found'\n}\n\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return msg\n }\n });\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 350, - "y": 100, - "wires": [ - [] - ] - }, - { - "id": "e978bf8c53d1f15a", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "Settings internal cam", - "info": "", - "x": 120, - "y": 40, - "wires": [] - }, - { - "id": "e9566588c5e40637", - "type": "inject", - "z": "1613373abaf77a2c", - "name": "4s/0.5", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "0.5", - "crontab": "", - "once": true, - "onceDelay": "10", - "topic": "Repeat", - "payload": "0.2", - "payloadType": "str", - "x": 120, - "y": 1160, - "wires": [ - [ - "95439678bb2df2a2" - ] - ] - }, - { - "id": "14f9617b5b301318", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "Take Preview Shot", - "func": "from time import time, sleep\nfrom OpenScan import load_str, load_bool, take_photo, camera, load_int,save\n\nstatus = load_str('status_internal_cam')\n\nif msg['flag'] == False and not 'Routine' in status:\n return\n\nmsg['payload']=\"/tmp/preview.jpg?ts=\"+str(int(time()*10))\n\nif status!=\"--READY--\" and status!=\"ERROR:flask\":\n return msg\n\nmsg['cropx'] = load_int('cam_cropx')\nmsg['cropy'] = load_int('cam_cropy')\nmsg['rotation'] = load_int('cam_rotation')\nmsg['filepath_in'] = 'tmp/tmp.jpg'\nmsg['filepath_out'] = 'tmp/preview.jpg'\nmsg['preview'] = True\n\ntake_photo('tmp/tmp.jpg')\n\ntry:\n camera('/crop',msg)\nexcept:\n save('status_internal_cam','ERROR: flask')\n pass\n \n\nreturn msg\n", - "outputs": 1, - "x": 450, - "y": 1160, - "wires": [ - [ - "948a3ae4444685f2", - "8f5d87ce24c40b11" - ] - ] - }, - { - "id": "1118d0965ff7c40b", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 3, - "width": 3, - "height": 1, - "name": "projectname", - "label": "Projectname", - "format": "", - "layout": "row-left", - "className": "", - "x": 670, - "y": 500, - "wires": [] - }, - { - "id": "82c8ad50ecfbc755", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 11, - "width": 3, - "height": 1, - "name": "ringlight", - "label": "Ringlight", - "format": "", - "layout": "row-left", - "className": "", - "x": 660, - "y": 700, - "wires": [] - }, - { - "id": "33d94a04b96a2de0", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "global.set('flag', false)\n\nvar file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\n\n\nif (data === 'no camera found'){\n return\n}\n\nmsg.enabled = true\nreturn msg\n\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 290, - "y": 920, - "wires": [ - [ - "579f2211199fd6ab" - ] - ] - }, - { - "id": "c1c044f3c2139f68", - "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "msg.enabled = false\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 750, - "y": 960, - "wires": [ - [ - "579f2211199fd6ab" - ] - ] - }, - { - "id": "9a368472a72fbc48", - "type": "comment", - "z": "1613373abaf77a2c", - "name": "preview arducam with focus", - "info": "", - "x": 160, - "y": 1100, - "wires": [] - }, - { - "id": "8f5d87ce24c40b11", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "preview_arducam", - "order": 8, - "width": 10, - "height": 12, - "format": "
\n\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 670, - "y": 1160, - "wires": [ - [] - ] - }, - { - "id": "282efe64332193c8", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "focus", - "func": "from OpenScan import load_str\n\nif load_str('camera') != 'imx519':\n return\n\nfrom Arducam import Focuser\n\n\nif msg['focuser'] == True:\n focuser = Focuser('/dev/v4l-subdev1')\n focuser.write(msg['focus'])\n return msg", - "outputs": 1, - "x": 1110, - "y": 1320, - "wires": [ - [] - ] - }, - { - "id": "64b16ef47ab6d859", - "type": "ui_switch", - "z": "1613373abaf77a2c", - "name": "MF", - "label": "", - "tooltip": "", - "group": "90223f7ddc082321", - "order": 3, - "width": 1, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "topic", - "topicType": "msg", - "style": "", - "onvalue": "false", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "true", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 150, - "y": 1260, - "wires": [ - [ - "f017f67a8d4a3750" - ] - ] - }, - { - "id": "f017f67a8d4a3750", - "type": "function", - "z": "1613373abaf77a2c", - "name": "enable", - "func": "let fs = global.get('fs');\nfilepath = '/home/pi/OpenScan/settings/';\n\nvar file = 'status_internal_cam'\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data != '--READY--'){\n return\n}\n\nfile = 'cam_AFmode'\ncontent = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});\n\nglobal.set('AF',msg.payload)\nmsg.enabled = false\nif (msg.payload == false){\n msg.enabled = true\n}\nif (msg.payload == true){\n file = 'cam_focus1'\n content = String(0)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n file = 'cam_focus2'\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n \n file = 'cam_stacksize'\n content = String(2)\n fs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });\n global.set('focus1', 0)\n global.set('focus2', 0)\n\n}\n\n\nmsg.focus = global.get('focus')\nmsg.payload = 'down'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 1260, - "wires": [ - [ - "5c39bd09.702d84", - "74521cf72050b515", - "b70e8c24ee011258" - ] - ] - }, - { - "id": "65145c939b6647e2", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "", - "links": [ - "960912e90ba5b5bc" - ], - "x": 55, - "y": 1260, - "wires": [ - [ - "64b16ef47ab6d859" - ] - ] - }, - { - "id": "5ea18678.975138", - "type": "trigger", - "z": "1613373abaf77a2c", - "name": "20ms", - "op1": "", - "op2": "0", - "op1type": "pay", - "op2type": "str", - "duration": "-20", - "extend": false, - "overrideDelay": false, - "units": "ms", - "reset": "", - "bytopic": "all", - "topic": "topic", - "outputs": 1, - "x": 730, - "y": 1300, - "wires": [ - [ - "fd93843e238cc9ce" - ] - ] - }, - { - "id": "5c39bd09.702d84", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "F+", - "order": 4, - "width": 1, - "height": 1, - "format": " ", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 410, - "y": 1260, - "wires": [ - [ - "dcfb5cce.0431a" - ] - ] - }, - { - "id": "dcfb5cce.0431a", - "type": "switch", - "z": "1613373abaf77a2c", - "name": "", - "property": "payload", - "propertyType": "msg", - "rules": [ - { - "t": "eq", - "v": "1", - "vt": "num" - }, - { - "t": "eq", - "v": "-1", - "vt": "num" - }, - { - "t": "eq", - "v": "up", - "vt": "str" - } - ], - "checkall": "true", - "repair": false, - "outputs": 3, - "x": 550, - "y": 1280, - "wires": [ - [ - "5ea18678.975138", - "f4a41b1e7b221486" - ], - [ - "5ea18678.975138", - "f4a41b1e7b221486" - ], - [ - "8cdd0a6b.40bcd8" - ] - ] - }, - { - "id": "8cdd0a6b.40bcd8", - "type": "change", - "z": "1613373abaf77a2c", - "name": "", - "rules": [ - { - "t": "set", - "p": "reset", - "pt": "msg", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 560, - "y": 1340, - "wires": [ - [ - "5ea18678.975138", - "e9b3837b1ffb0360" - ] - ] - }, - { - "id": "74521cf72050b515", - "type": "ui_template", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "name": "F-", - "order": 5, - "width": 1, - "height": 1, - "format": " ", - "storeOutMessages": true, - "fwdInMessages": true, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 410, - "y": 1300, - "wires": [ - [ - "dcfb5cce.0431a" - ] - ] - }, - { - "id": "7219f62c9fdc6753", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 6, - "width": 2, - "height": 1, - "name": "", - "label": "{{msg.payload}}", - "format": "", - "layout": "col-center", - "className": "", - "x": 1130, - "y": 1280, - "wires": [] - }, - { - "id": "b70e8c24ee011258", - "type": "function", - "z": "1613373abaf77a2c", - "name": "global", - "func": "if (msg.payload == 'down'){\n msg.enabled = false\n msg.payload = ' '\n msg.focuser = global.get('focuser')\n return msg\n}\n\n\nmsg.enabled = true\n\nsign = msg.payload\nfocus = global.get('focus')\nif (focus > 3000){\n focusstep = 5\n}\nelse if (focus <=3000 && focus > 2000){\n focusstep = 3\n}\nelse{\n focusstep = 2\n}\n\n\nfocus = focus + sign * focusstep\n\nsign = msg.payload\nif (focus > 4000){\n distance = 6\n focus = 4000\n}\nelse if (focus > 1200 && focus <= 4000){\n distance = 737086 * Math.pow(focus, -1.4096)\n}\nelse if (focus <= 1200){\n distance = 999\n if (focus <=0){\n focus = 0\n }\n}\n\n\nglobal.set('focus', focus)\nmsg.focus = focus\nmsg.distance = distance\ndistance = distance * 10\nmsg.focuser = global.get('focuser')\nmsg.payload = String(distance.toFixed(1)) + 'mm'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 970, - "y": 1300, - "wires": [ - [ - "7219f62c9fdc6753", - "282efe64332193c8", - "704a9f89089d1f25" - ] - ] - }, - { - "id": "f4a41b1e7b221486", - "type": "change", - "z": "1613373abaf77a2c", - "name": "focuser f", - "rules": [ - { - "t": "set", - "p": "focuser", - "pt": "global", - "to": "false", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 740, - "y": 1260, - "wires": [ - [] - ] - }, - { - "id": "e9b3837b1ffb0360", - "type": "change", - "z": "1613373abaf77a2c", - "name": "focuser t", - "rules": [ - { - "t": "set", - "p": "focuser", - "pt": "global", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 740, - "y": 1340, - "wires": [ - [] - ] - }, - { - "id": "fd93843e238cc9ce", - "type": "delay", - "z": "1613373abaf77a2c", - "name": "10ms", - "pauseType": "delay", - "timeout": "20", - "timeoutUnits": "milliseconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": false, - "allowrate": false, - "outputs": 1, - "x": 850, - "y": 1300, - "wires": [ - [ - "b70e8c24ee011258" - ] - ] - }, - { - "id": "dfbfe28bac5c4221", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "90223f7ddc082321", - "order": 2, - "width": 1, - "height": 1, - "name": "MF", - "label": "MF", - "format": "", - "layout": "col-center", - "className": "", - "x": 150, - "y": 1300, - "wires": [] - }, - { - "id": "704a9f89089d1f25", - "type": "function", - "z": "1613373abaf77a2c", - "name": "save", - "func": "var file = 'cam_focus'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.focus)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 1110, - "y": 1360, - "wires": [ - [] - ] - }, - { - "id": "917a194be245384a", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable projectname", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 540, - "wires": [ - [ - "f4b3112a9ec6c487" - ] - ] - }, - { - "id": "65cef204b16f8741", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable shutter", - "links": [ - "2d76e5617f13cd6c", - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 580, - "wires": [ - [ - "84d6b96c8ebaac96" - ] - ] - }, - { - "id": "2aea1727dbea76ce", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable cropx", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 620, - "wires": [ - [ - "9c6b48b7b4cc4e1a" - ] - ] - }, - { - "id": "4f212b44aa487945", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "enable cropy", - "links": [ - "a0ba1aa77c5c8b7c", - "a42c12e94f65fa01" - ], - "x": 55, - "y": 660, - "wires": [ - [ - "c470fd0b15356206" - ] - ] - }, - { - "id": "6d1e12f51f9af0b6", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "start camchk", - "links": [ - "960912e90ba5b5bc" - ], - "x": 55, - "y": 100, - "wires": [ - [ - "12f1399b240830bf" - ] - ] - }, - { - "id": "8ebd1dcb5db156ed", - "type": "ui_text", - "z": "1613373abaf77a2c", - "group": "7aaf184330605300", - "order": 2, - "width": 6, - "height": 1, - "name": "", - "label": "Current Status:", - "format": " {{msg.payload}} ", - "layout": "row-spread", - "className": "", - "x": 320, - "y": 160, - "wires": [] - }, - { - "id": "94a7aec739f9266b", - "type": "function", - "z": "1613373abaf77a2c", - "name": "loadS", - "func": "var file = 'status_internal_cam'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\n\nif (data === 'no camera found'){\n msg.color = 'red'\n}\n\nreturn msg\n\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 170, - "y": 160, - "wires": [ - [ - "8ebd1dcb5db156ed" - ] - ] - }, - { - "id": "2415272f42ce468c", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "start status", - "links": [ - "6c6ef2255a7d39e5" - ], - "x": 55, - "y": 160, - "wires": [ - [ - "94a7aec739f9266b" - ] - ] - }, - { - "id": "a1e14624058e74cd", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "start routine settings", - "links": [ - "960912e90ba5b5bc" - ], - "x": 55, - "y": 500, - "wires": [ - [ - "f4b3112a9ec6c487", - "107a030938cbfea9", - "84d6b96c8ebaac96", - "9c6b48b7b4cc4e1a", - "c470fd0b15356206", - "9e30e33a1520fee0" - ] - ] - }, - { - "id": "1daf9e3a5bd5ab48", - "type": "function", - "z": "1613373abaf77a2c", - "name": "msg", - "func": "global.set('flag_pw', true)\nglobal.set('flag', true)\nmsg.enabled = true\nreturn msg\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 750, - "y": 880, - "wires": [ - [ - "fb13752beddee9f2" - ] - ] - }, - { - "id": "6d15f717d5a11002", - "type": "function", - "z": "1613373abaf77a2c", - "name": "disable", - "func": "msg.enabled = false\nreturn msg\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 300, - "y": 800, - "wires": [ - [ - "e9b13dfd9f8d3711" - ] - ] - }, - { - "id": "db7eea74d3bf892b", - "type": "ui_toast", - "z": "1613373abaf77a2c", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "Finish", - "cancel": "Continue", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 450, - "y": 840, - "wires": [ - [ - "0b8661103366f834" - ] - ] - }, - { - "id": "0b8661103366f834", - "type": "python3-function", - "z": "1613373abaf77a2c", - "name": "continue", - "func": "from os import system\nfrom os.path import isfile\n\nif msg['payload'] == 'Continue':\n msg['enabled'] = True\n return msg,None\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp/tmp.jpg'\nzippath = basepath + 'tmp/tmp.zip'\nprojectcode = msg['projectcode']\n\nsystem('mv '+ zippath + ' ' + basepath + 'scans/' + projectcode + '.zip')\n\nif isfile(zippath):\n system('rm ' + zippath)\n\nreturn None, msg", - "outputs": 2, - "x": 600, - "y": 880, - "wires": [ - [ - "431f917c2541ae48", - "579f2211199fd6ab" - ], - [ - "1daf9e3a5bd5ab48", - "579f2211199fd6ab" - ] - ] - }, - { - "id": "482bc06e02eec5b9", - "type": "link in", - "z": "1613373abaf77a2c", - "name": "preview", - "links": [ - "960912e90ba5b5bc", - "fb13752beddee9f2" - ], - "x": 55, - "y": 1200, - "wires": [ - [ - "95439678bb2df2a2" - ] - ] - }, - { - "id": "ea54fcc2.cfcc2", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "get dirs", - "func": "from glob import glob\nimport os\nfrom zipfile import ZipFile\n\ndef set_stats(stat):\n try:\n with open(directory+set[:-4]+\"/\"+stat,\"r\") as file:\n stat=file.read()\n except:\n stat=\"\"\n return stat\n\ntable=[]\ndirectory=\"/home/pi/OpenScan/scans/\"\n\nfor d in glob(directory+\"*.zip\"):\n set=os.path.basename(d)\n\n try:\n with ZipFile(d, 'r') as f:\n photos = len(f.namelist())\n\n size = float(int(float(os.path.getsize(d))/100000))/10\n size_full= os.path.getsize(d)\n status=set_stats(\"status\")\n expiration=set_stats(\"expiration\")\n download=set_stats(\"download\")\n \n if len(download)!=0:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Download\":\"RESULT\",\n \"Size_full\":size_full,\n \n })\n else:\n table.append({\n \"Set\":set,\n \"Photos\":photos,\n \"Size\":str(size)+\"MB\",\n \"Date\":set[:16],\n \"Name\":(set[20:-4]),\n \"Status\":status,\n \"Size_full\":size_full,\n \n })\n except:\n pass\n\nmsg['payload']=table\nmsg['topic']=\"\"\nreturn msg", - "outputs": 1, - "x": 480, - "y": 180, - "wires": [ - [ - "b9a3a0f9.bcbea" - ] - ] - }, - { - "id": "2f4c0f98.dee2", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "filelist", - "links": [ - "960912e90ba5b5bc", - "a4f09e25.02569", - "ed35109311335099", - "fb13752beddee9f2" - ], - "x": 355, - "y": 140, - "wires": [ - [ - "ea54fcc2.cfcc2" - ] - ] - }, - { - "id": "b9a3a0f9.bcbea", - "type": "ui_table", - "z": "4981d84ef1a366d1", - "group": "b5fdd57b.15eda8", - "name": "", - "order": 1, - "width": 13, - "height": 7, - "columns": [ - { - "field": "Date", - "title": "Date", - "width": "150", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Name", - "title": "Name", - "width": "210", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Photos", - "title": "Photos", - "width": "80", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Size", - "title": "Size", - "width": "80", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - }, - { - "field": "Status", - "title": "Status", - "width": "140", - "align": "center", - "formatter": "plaintext", - "formatterParams": { - "target": "_blank" - } - } - ], - "outputs": 1, - "cts": true, - "x": 610, - "y": 180, - "wires": [ - [ - "50710948.71c308", - "4082b136.dae18", - "834046a4.647938", - "0c387c0291d6c131" - ] - ] - }, - { - "id": "952ce286.4ffd4", - "type": "ui_text", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "order": 3, - "width": 6, - "height": 1, - "name": "Status", - "label": "Status", - "format": "{{msg.status}}", - "layout": "row-spread", - "className": "", - "x": 250, - "y": 60, - "wires": [] - }, - { - "id": "d4383424.7807c8", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "upload", - "func": "import os\nfrom OpenScan import OpenScanCloud, load_str, load_int, save\n\nbasedir = '/home/pi/OpenScan/'\n\nif load_str(\"feedback_terms\")==\"False\":\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic'] = 'OpenScanCloud - Terms of Use'\n return None,msg\n\nmsg = msg['payload']\n\ndef upload(filelist, ulinks):\n i = 0\n for file in filelist:\n link = ulinks[i]\n save('status_cloud', 'uploading ' + str(i+1) + '/' + str(len(filelist)))\n cmd = 'curl -# -X POST ' + link + ' --header Content-Type:application/octet-stream --data-binary @\"' + file + '\" 2>&1 | tee /home/pi/OpenScan/settings/status_uploadprogress'\n i = i+1\n os.system(cmd)\n\n########\nif not os.path.isfile(basedir + 'settings/token'):\n msg['flag'] = True\n save('status_cloud', 'please enter token first')\n return msg\nwith open(basedir + 'settings/token', 'r') as file:\n token = file.read().strip('\\n')\n\n########\nr = OpenScanCloud('getTokenInfo', {'token':token})\n\nif r.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n save('status_cloud', 'invalid/missing token')\n return None,msg\nelif r.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nmsg1 = r.json()\n\n########\nif msg['Photos'] > msg1['limit_photos'] or msg['Size_full'] > msg1['limit_filesize']:\n msg['flag'] = True\n save('status_cloud', 'limit(s) exceeded')\n return msg\n\n########\ntemp = OpenScanCloud('getProjectInfo', {'token':token, 'project':msg['Set']})\nif temp.status_code not in (200,401):\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nif temp.status_code != 401:\n temp = temp.json()\n if 'status' in temp:\n if temp['status'] != 'created':\n save('status_cloud','already exists')\n with open(basedir + 'scans/' + msg['Set'][:-4] + '/status', 'w') as file:\n file.write(temp['status'])\n return msg\n#####\n\nmsg2={}\nmsg2['token'] = token\nmsg2['parts'] = 1\nmsg['partslist']=[]\n\n#######\nsize_to_split = load_int('osc_splitsize')\n\nif msg['Size_full'] > size_to_split:\n tempdir = basedir + 'tmp/split/'\n if os.path.isdir(tempdir):\n os.system('rm -r ' + tempdir)\n os.mkdir(tempdir)\n save('status_cloud', 'zipping files, please wait ...')\n cmd = 'split -b ' + str(size_to_split) + ' ' + basedir + 'scans/' + msg['Set'] + ' ' + tempdir + msg['Set']\n os.system(cmd)\n save('status_cloud', 'zip done')\n list = os.listdir(tempdir)\n for l in list:\n msg['partslist'].append(tempdir + l)\n msg['partslist'].sort()\n msg2['parts']=len(msg['partslist'])\nelse:\n msg['partslist'] = [basedir + 'scans/' +msg['Set']]\n\n#######\nmsg2['photos'] = msg['Photos']\nmsg2['filesize'] = msg['Size_full']\nmsg2['project'] = msg['Set']\n\nr = OpenScanCloud('createProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Connection to OpenScanCloud failed'\n msg['payload'] = 'Please check your internet connection'\n return None,msg\n\nmsg1 = r.json()\n\nif not os.path.isdir(basedir+ 'scans/' + msg['Set'][:-4]):\n os.mkdir(basedir+ 'scans/' + msg['Set'][:-4])\nwith open(basedir+ 'scans/' + msg['Set'][:-4]+'/status', 'w+') as file:\n file.write('prepared')\n\nsave('status_cloud', 'uploading')\nupload(msg['partslist'], msg1['ulink'])\n\nr = OpenScanCloud('startProject', msg2)\nif r.status_code != 200:\n msg['topic'] = 'Upload failed'\n msg['payload'] = 'please try again'\n save('status_cloud', 'upload failed')\n return None,msg\n\nsave('status_cloud', 'uploaded')\n\nsave('status_cloud', 'project started')\n\ntry:\n os.system('rm -r ' + tempdir)\nexcept:\n pass\n\nreturn msg", - "outputs": 2, - "x": 530, - "y": 420, - "wires": [ - [ - "9a132ab1.b21658" - ], - [ - "3d16b3789632784d", - "9a132ab1.b21658" - ] - ] - }, - { - "id": "50710948.71c308", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "set", - "rules": [ - { - "t": "set", - "p": "set", - "pt": "global", - "to": "payload", - "tot": "msg" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 750, - "y": 180, - "wires": [ - [ - "ada1b6f7cccc9344" - ] - ] - }, - { - "id": "834046a4.647938", - "type": "ui_text", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "order": 4, - "width": 6, - "height": 1, - "name": "Set", - "label": "Set:", - "format": "{{msg.payload.Name}}", - "layout": "row-spread", - "className": "", - "x": 750, - "y": 220, - "wires": [] - }, - { - "id": "9a132ab1.b21658", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "flag.true", - "rules": [ - { - "t": "set", - "p": "flag", - "pt": "global", - "to": "true", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 700, - "y": 420, - "wires": [ - [ - "8689e938.dd9e38" - ] - ] - }, - { - "id": "3c67e97b.9d19a6", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "enable", - "func": "if (global.get('flag') === false){\n msg.enabled = false\n msg.color=\"white\"\n}\nelse{\n msg.enabled = true\n msg.color=\"red\"\n \n}\n\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 130, - "y": 340, - "wires": [ - [ - "7a93d1e18254685c", - "e434ef42bd6b92e8", - "d5d840183025d91b", - "ab9e90ab5a53a0dd", - "478994f671a3907d" - ] - ] - }, - { - "id": "bfc01f26.c32cf", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "flag.false", - "rules": [ - { - "t": "set", - "p": "flag", - "pt": "global", - "to": "false", - "tot": "bool" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 420, - "y": 460, - "wires": [ - [ - "f20f2dbc.0f123" - ] - ] - }, - { - "id": "b33d604c.5f1a6", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "enable cloud", - "links": [ - "4082b136.dae18", - "8689e938.dd9e38", - "e9b13dfd9f8d3711", - "f20f2dbc.0f123", - "fb13752beddee9f2" - ], - "x": 35, - "y": 340, - "wires": [ - [ - "3c67e97b.9d19a6" - ] - ] - }, - { - "id": "f6bd1a04.470838", - "type": "change", - "z": "4981d84ef1a366d1", - "name": "set", - "rules": [ - { - "t": "set", - "p": "payload", - "pt": "msg", - "to": "set", - "tot": "global" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 410, - "y": 420, - "wires": [ - [ - "d4383424.7807c8" - ] - ] - }, - { - "id": "4082b136.dae18", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "b33d604c.5f1a6", - "87574a42938afec4" - ], - "x": 715, - "y": 140, - "wires": [] - }, - { - "id": "f20f2dbc.0f123", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "b33d604c.5f1a6", - "149e2e46b9623a2d" - ], - "x": 515, - "y": 460, - "wires": [] - }, - { - "id": "8689e938.dd9e38", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "8367cfa0bf5bc5df", - "b33d604c.5f1a6", - "149e2e46b9623a2d" - ], - "x": 795, - "y": 420, - "wires": [] - }, - { - "id": "15de0ebb.616d61", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 550, - "y": 380, - "wires": [ - [ - "a7d89487.ee8858" - ] - ] - }, - { - "id": "a7d89487.ee8858", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "del", - "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\ntry:\n os.remove(dir+msg['Set'])\n shutil.rmtree(dir+msg['Set'][:-4])\nexcept:\n pass\nreturn msg", - "outputs": 1, - "x": 690, - "y": 380, - "wires": [ - [ - "a4f09e25.02569" - ] - ] - }, - { - "id": "a4f09e25.02569", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "2f4c0f98.dee2", - "c20357dd.374108", - "e9aab326.a6896", - "edd22cc7.befe1", - "19b81967.49db87", - "8ee1b3bb.7b0b3", - "d5246b3cc796afc6" - ], - "x": 775, - "y": 360, - "wires": [] - }, - { - "id": "7a93d1e18254685c", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "809c9427e14e2448", - "92c98e6ce7cd25f9" - ], - "x": 235, - "y": 460, - "wires": [] - }, - { - "id": "4d99c601c9881680", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "refresh", - "func": "from time import sleep\nimport os\nfrom OpenScan import load_str, OpenScanCloud, save, load_bool\n\nbasepath = '/home/pi/OpenScan/scans/'\n\nif load_bool(\"terms\")==False:\n msg['payload']=\"Please read and agree to the Terms of Use (See Settings Menu) before you can use the OpenScanCloud\"\n msg['topic']='OpenScanCloud - Terms of Use'\n return None,msg\n\nsave('status_cloud','refreshing')\ntoken = load_str('token')\n\ntest = OpenScanCloud('getTokenInfo',{'token':token})\nif test.status_code == 400:\n msg['topic'] = 'Invalid Token'\n msg['payload'] = 'Please enter a valid token (settings --> OpenScanCloud)'\n return None,msg\nelif test.status_code == 200:\n pass\nelse:\n msg['topic'] = 'Connection Error'\n msg['payload'] = 'Not able to establish a connection to OpenScanCloud.'\n return None,msg\n\nstats = test.json()\nfor i in stats:\n save('osc_'+i, stats[i])\n pass\n\nmsg={}\nprojects = []\nfor i in os.listdir(basepath):\n if os.path.isdir(basepath + i):\n if os.path.isfile(basepath + i + '/status'):\n with open(basepath + i + '/status', 'r') as file:\n status = file.read().strip('\\n')\n if status in ['expired', 'processing done', 'processing failed']:\n continue\n projects.append(i)\n\nfor p in projects:\n r = OpenScanCloud('getProjectInfo',{'token':token, 'project':p+'.zip'})\n if r.status_code == 200:\n answer = r.json()\n if answer == {}:\n os.system('sudo rm -r ' + basepath + p)\n else:\n with open(basepath + p + '/status', 'w+') as file:\n file.write(answer['status'])\n with open(basepath + p + '/download', 'w+') as file:\n file.write(answer['dlink'])\n\nmsg['list'] = projects\nsleep(0.5)\nsave('status_cloud','ready')\nreturn msg, None\n", - "outputs": 2, - "x": 320, - "y": 180, - "wires": [ - [ - "ea54fcc2.cfcc2", - "b42e061fb1f1f3d7" - ], - [ - "6434e713f088012b" - ] - ] - }, - { - "id": "372e95797a3f2f3b", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "limit :)", - "func": "from time import sleep\n\nmsg2={}\nmsg2['enabled'] = True\n\nmsg['enabled'] = False\nnode.send(msg)\n\nwait = 15\n\nfor i in range (wait):\n msg['text'] = ' ('+ str(wait - i)+')'\n node.send(msg)\n\nmsg['enabled'] = True\nmsg['text']=\"\"\n\n\nreturn msg", - "outputs": 1, - "x": 90, - "y": 220, - "wires": [ - [ - "573edbfdb7500ddc" - ] - ] - }, - { - "id": "573edbfdb7500ddc", - "type": "delay", - "z": "4981d84ef1a366d1", - "name": "", - "pauseType": "rate", - "timeout": "5", - "timeoutUnits": "seconds", - "rate": "1", - "nbRateUnits": "1", - "rateUnits": "second", - "randomFirst": "1", - "randomLast": "5", - "randomUnits": "seconds", - "drop": false, - "allowrate": false, - "outputs": 1, - "x": 230, - "y": 220, - "wires": [ - [ - "c46e10b9c201913e" - ] - ] - }, - { - "id": "dacb1f078b624e10", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 550, - "y": 340, - "wires": [ - [ - "c8d65cc7c2ff7c36" - ] - ] - }, - { - "id": "92c98e6ce7cd25f9", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "7a93d1e18254685c", - "bd75f33b8a57c522" - ], - "x": 35, - "y": 180, - "wires": [ - [ - "c46e10b9c201913e" - ] - ] - }, - { - "id": "3d16b3789632784d", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "Terms", - "x": 690, - "y": 460, - "wires": [ - [] - ] - }, - { - "id": "6434e713f088012b", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "Terms", - "x": 470, - "y": 220, - "wires": [ - [] - ] - }, - { - "id": "c8d65cc7c2ff7c36", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "del", - "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if os.path.isdir(dir + i):\n shutil.rmtree(dir + i)\n else:\n os.remove(dir + i)\n\nreturn msg", - "outputs": 1, - "x": 690, - "y": 340, - "wires": [ - [ - "a4f09e25.02569" - ] - ] - }, - { - "id": "6d471a5210505276", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "read", - "func": "var file = 'status_cloud'\nvar file2 = 'status_uploadprogress'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nstatus = String(data);\n\nif (status.substr(0,9) === 'uploading'){\n data = fs.readFileSync(filepath+file2, 'utf8');\n progress = data.substr(data.length - 6)\n if (progress.substr(progress.length -1) === '%'){\n status = status + ' (' + progress + ')'\n }\n}\nmsg.status = status\nreturn msg\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 130, - "y": 60, - "wires": [ - [ - "952ce286.4ffd4" - ] - ] - }, - { - "id": "f4e9a4bd79b4221f", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "msg", - "func": "msg.payload = 'Are you sure to delete ALL saved image sets? This can not be undone!'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 410, - "y": 340, - "wires": [ - [ - "dacb1f078b624e10" - ] - ] - }, - { - "id": "2806bf08ea21216d", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "msg", - "func": "msg.Set=global.get('set').Set\nmsg.payload = 'Are you sure to delete the set and ALL associated files: ' + msg.Set + '?'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 410, - "y": 380, - "wires": [ - [ - "15de0ebb.616d61" - ] - ] - }, - { - "id": "61990987acd0f263", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "6c6ef2255a7d39e5" - ], - "x": 35, - "y": 60, - "wires": [ - [ - "6d471a5210505276" - ] - ] - }, - { - "id": "e8e488a6dd5d0b33", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "Download", - "order": 5, - "width": 3, - "height": 1, - "format": "\n
Download\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 900, - "y": 260, - "wires": [ - [] - ] - }, - { - "id": "0c387c0291d6c131", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "msg", - "func": "msg.download = '/scans/' + String(msg.payload.Set)\nreturn msg;", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 750, - "y": 260, - "wires": [ - [ - "e8e488a6dd5d0b33" - ] - ] - }, - { - "id": "e5f38b4a07a5e278", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "", - "links": [ - "960912e90ba5b5bc" - ], - "x": 655, - "y": 220, - "wires": [ - [ - "834046a4.647938" - ] - ] - }, - { - "id": "e434ef42bd6b92e8", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "upload2", - "order": 6, - "width": 3, - "height": 1, - "format": "upload", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 280, - "y": 420, - "wires": [ - [ - "f6bd1a04.470838", - "bfc01f26.c32cf" - ] - ] - }, - { - "id": "c46e10b9c201913e", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "refresh", - "order": 1, - "width": 3, - "height": 1, - "format": "refresh{{msg.text}}", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 160, - "y": 180, - "wires": [ - [ - "372e95797a3f2f3b", - "4d99c601c9881680" - ] - ] - }, - { - "id": "d5d840183025d91b", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "del set", - "order": 8, - "width": 2, - "height": 1, - "format": "delete set", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 270, - "y": 380, - "wires": [ - [ - "2806bf08ea21216d" - ] - ] - }, - { - "id": "ab9e90ab5a53a0dd", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "del ", - "order": 9, - "width": 2, - "height": 1, - "format": "delete all", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 270, - "y": 340, - "wires": [ - [ - "f4e9a4bd79b4221f" - ] - ] - }, - { - "id": "478994f671a3907d", - "type": "ui_template", - "z": "4981d84ef1a366d1", - "group": "db43d646.2074c8", - "name": "combine", - "order": 7, - "width": 2, - "height": 1, - "format": "combine", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 280, - "y": 500, - "wires": [ - [ - "51bfd0fb7b1d292e" - ] - ] - }, - { - "id": "189c1eed09624a7b", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "combine", - "func": "combine = global.get('combine')\ncombine_set = global.get('set').Set\n\nif (combine === true && global.get('combine_set') !== combine_set){\n msg.set1 = global.get('combine_set')\n msg.set2 = combine_set\n global.set('combine', false)\n msg.topic = 'Combine the following two sets:'\n msg.payload = msg.set1 + '
' + msg.set2 + '
FILES WILL BE MERGED INTO ON FILE!'\n return msg\n}\nglobal.set('combine_set' , combine_set)\n\n", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 280, - "y": 540, - "wires": [ - [ - "1493398979a63775" - ] - ] - }, - { - "id": "51bfd0fb7b1d292e", - "type": "function", - "z": "4981d84ef1a366d1", - "name": "combine", - "func": "global.set('combine', true)\ncombine_set = global.get('set').Set\nmsg.topic = 'Merge two sets into one (can not be undone)!'\nmsg.payload = combine_set\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 420, - "y": 500, - "wires": [ - [] - ] - }, - { - "id": "da325be8e74179be", - "type": "python3-function", - "z": "4981d84ef1a366d1", - "name": "combine", - "func": "from os.path import getsize\nfrom shutil import copy\nfrom os import rename, remove\nimport zipfile as z\nfrom OpenScan import save\n\nfrom time import sleep\n\nif msg['payload'] != 'OK':\n return\n\nbasepath = '/home/pi/OpenScan/scans/'\ntmp1 = basepath + msg['set1']\ntmp2 = basepath + msg['set2']\n\nif getsize(tmp1) > getsize(tmp2):\n set1 = tmp1\n set2 = tmp2\nelse:\n set1 = tmp2\n set2 = tmp1\n\n#set 1 is larger and to be merged into\n\nzips = [set1, set2]\n\nwith z.ZipFile(set1, 'a') as z1:\n z2 = z.ZipFile(set2, 'r')\n i = 0\n for n in z2.namelist():\n i += 1\n n2 = n\n save('status_cloud','combining ' + str(i) + '/' + str(len(z2.namelist())))\n while 'X'+n in z1.namelist():\n n = 'X' + n\n z1.writestr('X'+n, z2.open(n2).read())\nsave('status_cloud','ready')\n\nos.rename(set1, set1[:-4] + 'X.zip')\nos.remove(set2)\n\nreturn msg", - "outputs": 1, - "x": 560, - "y": 540, - "wires": [ - [ - "ed35109311335099" - ] - ] - }, - { - "id": "ed35109311335099", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "809c9427e14e2448", - "2f4c0f98.dee2" - ], - "x": 655, - "y": 540, - "wires": [] - }, - { - "id": "1493398979a63775", - "type": "ui_toast", - "z": "4981d84ef1a366d1", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": true, - "className": "", - "topic": "", - "name": "Combine", - "x": 420, - "y": 540, - "wires": [ - [ - "da325be8e74179be" - ] - ] - }, - { - "id": "ada1b6f7cccc9344", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "combine", - "mode": "link", - "links": [ - "6dd356510c446cf4" - ], - "x": 835, - "y": 180, - "wires": [] - }, - { - "id": "6dd356510c446cf4", - "type": "link in", - "z": "4981d84ef1a366d1", - "name": "combine", - "links": [ - "ada1b6f7cccc9344" - ], - "x": 175, - "y": 540, - "wires": [ - [ - "189c1eed09624a7b" - ] - ] - }, - { - "id": "b42e061fb1f1f3d7", - "type": "link out", - "z": "4981d84ef1a366d1", - "name": "", - "mode": "link", - "links": [ - "397ab7f44b893c89" - ], - "x": 435, - "y": 140, - "wires": [] - }, - { - "id": "52858b4eceacc902", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "", - "group": "3b4bd36726be16d5", - "order": 4, - "width": 2, - "height": 1, - "passthru": false, - "label": "Terms", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 90, - "y": 300, - "wires": [ - [ - "f99ec8781a33ec7d" - ] - ] - }, - { - "id": "7dc39bd847d16ded", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "Agree", - "cancel": "Disagree", - "raw": true, - "className": "", - "topic": "", - "name": "", - "x": 410, - "y": 300, - "wires": [ - [ - "5f849178998d9082" - ] - ] - }, - { - "id": "cc3cb10f2ea3f8b8", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "blink Light1", - "func": "import RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nfrom OpenScan import ringlight\nfrom time import sleep\n\ndelay = 0.1\nringlight(2,False)\n\nfor i in range (5):\n ringlight(1,True)\n sleep(delay)\n ringlight(1,False)\n sleep(delay)", - "outputs": 1, - "x": 310, - "y": 420, - "wires": [ - [] - ] - }, - { - "id": "d114f4d4d7f31981", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "reboot", - "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('sudo reboot')\n", - "outputs": 1, - "x": 290, - "y": 380, - "wires": [ - [] - ] - }, - { - "id": "f52d4d86b39aeb6b", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "shutdown", - "func": "import os\nfrom time import sleep\nsleep(1.5)\nimport RPi.GPIO as GPIO\nGPIO.setwarnings(False)\nGPIO.cleanup()\nos.system('sudo shutdown -h now')", - "outputs": 1, - "x": 300, - "y": 460, - "wires": [ - [] - ] - }, - { - "id": "15a0a2f431ce55c3", - "type": "comment", - "z": "017bd4e4a428bee5", - "name": "General Settings", - "info": "", - "x": 120, - "y": 260, - "wires": [] - }, - { - "id": "87a403b9a09aa38d", - "type": "comment", - "z": "017bd4e4a428bee5", - "name": "Network", - "info": "", - "x": 120, - "y": 560, - "wires": [] - }, - { - "id": "ca4afadb5b21751f", - "type": "comment", - "z": "017bd4e4a428bee5", - "name": "Info Texts", - "info": "", - "x": 100, - "y": 120, - "wires": [] - }, - { - "id": "2a0f9919.4c9a86", - "type": "comment", - "z": "017bd4e4a428bee5", - "name": "OpenScanCloud", - "info": "", - "x": 140, - "y": 880, - "wires": [] - }, - { - "id": "27c6b221c90ed9e1", - "type": "exec", - "z": "017bd4e4a428bee5", - "command": "sudo iwlist wlan0 scan | grep ESSID | sed 's/ESSID://g;s/\"//g;s/^ *//;s/ *$//'", - "addpay": false, - "append": "", - "useSpawn": "false", - "timer": "", - "winHide": false, - "oldrc": false, - "name": "scan", - "x": 270, - "y": 720, - "wires": [ - [ - "b05cf92302a5c112" - ], - [ - "e9677b85856b5873" - ], - [] - ] - }, - { - "id": "b05cf92302a5c112", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "WIFI", - "func": "msg['options']=[]\n\nfor i in msg['payload'].split('\\n'):\n if i not in msg['options'] and i!=\"\":\n msg['options'].append(i)\n \nif len(msg['options']) != 0:\n msg['enabled']=True\n\nreturn msg", - "outputs": 1, - "x": 390, - "y": 700, - "wires": [ - [ - "59c9f67283ba1709" - ] - ] - }, - { - "id": "da5ddaf4cc25b8c8", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "search", - "group": "3b4bd36726be16d5", - "order": 11, - "width": 3, - "height": 1, - "passthru": false, - "label": "Search Wifi", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "true", - "payloadType": "bool", - "topic": "", - "topicType": "str", - "x": 110, - "y": 660, - "wires": [ - [ - "27c6b221c90ed9e1", - "51521bc6eb44cde5" - ] - ] - }, - { - "id": "59c9f67283ba1709", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "", - "label": "", - "tooltip": "", - "place": "Select Wifi", - "group": "3b4bd36726be16d5", - "order": 14, - "width": 6, - "height": 1, - "passthru": true, - "multiple": false, - "options": [], - "payload": "", - "topic": "", - "topicType": "str", - "className": "", - "x": 540, - "y": 660, - "wires": [ - [ - "2bb52656f9554dab" - ] - ] - }, - { - "id": "b2d7d6a730f7dca6", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Reset Wifi", - "group": "3b4bd36726be16d5", - "order": 12, - "width": 3, - "height": 1, - "passthru": false, - "label": "Reset Wifi", - "tooltip": "", - "color": "red", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "Delete all prior wifi connections? (You will need to reconnect to the OpenScan device by Ethernet or manually modify the wpa_supplicant.conf)", - "payloadType": "str", - "topic": "", - "topicType": "str", - "x": 130, - "y": 820, - "wires": [ - [ - "78985ac6d3bcdf60" - ] - ] - }, - { - "id": "c3b8faac9ebb2c80", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "Reset Wifi", - "func": "from time import sleep\n\nif msg['payload']!=\"Yes\":\n return\n\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('sudo mv '+ temp_dir + ' ' + wpa_dir)\nos.system('sudo wpa_cli -i wlan0 reconfigure')\nsleep(3)\nos.system('sudo systemctl restart nodered')\nreturn msg", - "outputs": 1, - "x": 460, - "y": 820, - "wires": [ - [] - ] - }, - { - "id": "78985ac6d3bcdf60", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "No", - "cancel": "Yes", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 290, - "y": 820, - "wires": [ - [ - "c3b8faac9ebb2c80" - ] - ] - }, - { - "id": "4f7f49b12c2d2572", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "add Wifi", - "func": "from time import sleep\nsleep(0.1)\n\nos.system('sudo wpa_cli -i wlan0 reconfigure')\n\nreturn msg", - "outputs": 1, - "x": 1340, - "y": 680, - "wires": [ - [] - ] - }, - { - "id": "ebcc98685059b9d4", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "password", - "x": 800, - "y": 660, - "wires": [ - [ - "68204a14528ab842" - ] - ] - }, - { - "id": "68204a14528ab842", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "if msg['payload'] == 'Cancel':\n return\n\nmsg['password'] = msg['payload']\nmsg['payload']='Enter country code (ISO 3166-1 alpha-2, see: Wikipedia)'\n\n\nreturn msg", - "outputs": 1, - "x": 930, - "y": 660, - "wires": [ - [ - "852edf901bdec9c5" - ] - ] - }, - { - "id": "852edf901bdec9c5", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "Save", - "cancel": "Cancel", - "raw": true, - "className": "", - "topic": "", - "name": "country", - "x": 1060, - "y": 660, - "wires": [ - [ - "1b09d634e3d9357b" - ] - ] - }, - { - "id": "1b09d634e3d9357b", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "modWPA", - "func": "if msg['payload'] == 'Cancel':\n return\n\nif len(msg['payload'])!=2:\n msg['payload'] = 'invalid country code'\n return msg,None\n\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\ntemp_dir = '/home/pi/OpenScan/tmp/wpa'\n\ncode = msg['payload'].upper()\nssid = msg['ssid']\npassword = msg['password']\n\nif len(code) != 2:\n msg['topic'] = 'ERROR'\n msg['payload'] = 'invalid country code (see ISO 3166-1 alpha-2)'\n return msg\n\nwith open(wpa_dir, 'r') as file:\n for i in file.readlines():\n if 'country=' in i:\n code_old=i.split('country=')[1][0:2]\n break\n\nwith open(wpa_dir, 'r') as file:\n wpa = file.read()\n if ssid in wpa:\n msg['topic'] = 'ERROR'\n msg['payload'] = 'Network already exists! If you have trouble connecting, please consider resetting the saved Wifi connections.'\n return msg\n wpa=wpa.replace('country=' + code_old, 'country=' + code)\n wpa=wpa + '\\nnetwork={\\n priority=10\\n ssid=\"'+ssid+'\"\\n psk=\"'+password+'\"\\n}\\n'\n\nwith open(temp_dir,'w+') as file:\n file.write(wpa)\nos.system('sudo mv '+temp_dir + ' ' + wpa_dir)\n\nmsg['topic'] = 'Updating Wifi'\nmsg['payload'] = 'reconnecting might take a moment'\nreturn msg,msg\n", - "outputs": 2, - "x": 1200, - "y": 660, - "wires": [ - [ - "03732a7d3b0c95aa" - ], - [ - "4f7f49b12c2d2572" - ] - ] - }, - { - "id": "03732a7d3b0c95aa", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 1350, - "y": 640, - "wires": [ - [] - ] - }, - { - "id": "e97d17c6590138e2", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Cloud", - "group": "3b4bd36726be16d5", - "order": 2, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

OpenScanCloud

OpenScanCloud is a free/donation-based cloud processing service, which will convert your photos into 3d models using latest photogrammetry technology. Feel free to support the project with a small donation at BuyMeACoffee.

The only requirement to use this service is a one-time, free-of-charge registration (which is solely an anti-spam measure). By filling out the registration form, you will receive an individual access token.

Register

In order to use the OpenScanCloud, you will have to enter your name and email. It might take 1-3 days to create the access token, which will be sent to your mail address. Please check your spam folder.

Enter Token

Please enter your individual token here in order to activate the cloud functionality. The token will be verified immediately. In case of any problems, please contact cloud@openscan.eu

Terms

Please read the terms of use to understand what will happen to your data, when using the OpenScanCloud service.

Token

A shorted version of your token will be displayed here. Please include a copy of this shorted token in any support requests cloud@openscan.eu

Credit (GB)

Each token comes with a given amount of 'credit' which is another measure against spam. The given number in Gigabyte indicates the amount of data, that you can process on the servers. 

IMPORTANT: The credit can be increased at any time by sending a (nice) mail to cloud@openscan.eu

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 250, - "y": 120, - "wires": [ - [ - "f304680180a23479" - ] - ] - }, - { - "id": "1969c709ef2fd1d5", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "order": 7, - "width": 0, - "height": 0, - "name": "", - "label": "Credit (GB):", - "format": "{{msg.credit}}", - "layout": "row-spread", - "className": "", - "x": 730, - "y": 1140, - "wires": [] - }, - { - "id": "397ab7f44b893c89", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "OSCparameters", - "links": [ - "960912e90ba5b5bc", - "9c51aa678f16980f", - "b42e061fb1f1f3d7" - ], - "x": 465, - "y": 1140, - "wires": [ - [ - "a7fd00943edc380b" - ] - ] - }, - { - "id": "bf6d941ad307ce22", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 270, - "y": 960, - "wires": [ - [ - "f22dfef37d5de773" - ] - ] - }, - { - "id": "f22dfef37d5de773", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "import re\n\nif msg['payload'] == 'Cancel':\n return\n\nmail = msg['payload']\nemail_regex = re.compile(r\"[^@]+@[^@]+\\.[^@]+\")\n\nif email_regex.match(mail) != None:\n msg['mail'] = mail\n msg['topic'] = 'OpenScanCloud Registration (2/3)'\n msg['payload'] = 'Enter your first name'\n return msg\nmsg['payload'] = 'invalid input'\nreturn None,msg\n", - "outputs": 2, - "x": 410, - "y": 960, - "wires": [ - [ - "54602ee49ca022e7" - ], - [ - "1505f3e72f971081" - ] - ] - }, - { - "id": "1505f3e72f971081", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 550, - "y": 1000, - "wires": [ - [] - ] - }, - { - "id": "54602ee49ca022e7", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 550, - "y": 960, - "wires": [ - [ - "f9efcb87b74abbd4" - ] - ] - }, - { - "id": "510dbe4d76253bd6", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "SUBMIT", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 830, - "y": 960, - "wires": [ - [ - "600b2306caed1640" - ] - ] - }, - { - "id": "600b2306caed1640", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "import requests\nimport os\nfrom OpenScan import OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\nmsg['lastname'] = msg['payload']\n\nmsg2 = {}\n\nfor i in ['forename','lastname','mail']:\n msg2[i] = msg[i]\n\nr = OpenScanCloud('requestToken',msg2)\n\nstatus = r.status_code\n\nmsg['topic'] = 'OpenScanCloud Registration - Success'\nmsg['payload'] = 'registration done, you will get an email with your token within the next one or two days :)'\n\nif status != 200:\n msg['topic'] = 'OpenScanCloud Registration - Failed'\n msg['payload'] = 'Registration failed, please try again.'\n\nmsg['status'] = status\n\nreturn msg", - "outputs": 1, - "x": 970, - "y": 960, - "wires": [ - [ - "bbad1ab5f8f63fb7" - ] - ] - }, - { - "id": "d34cd203725bac15", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Register", - "group": "3b4bd36726be16d5", - "order": 5, - "width": 2, - "height": 1, - "passthru": false, - "label": "Register", - "tooltip": "", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "Please enter your email address:", - "payloadType": "str", - "topic": "Requesting an OpenScanCloud Token", - "topicType": "str", - "x": 120, - "y": 960, - "wires": [ - [ - "bf6d941ad307ce22" - ] - ] - }, - { - "id": "bbad1ab5f8f63fb7", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 1110, - "y": 960, - "wires": [ - [] - ] - }, - { - "id": "a7fd00943edc380b", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "from OpenScan import load_int\n\nmsg = {}\n\ntry:\n msg['credit'] = float(int(load_int('osc_credit')/10000000))/100\n return msg\nexcept:\n pass", - "outputs": 1, - "x": 590, - "y": 1140, - "wires": [ - [ - "1969c709ef2fd1d5" - ] - ] - }, - { - "id": "f99ec8781a33ec7d", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.payload = 'This is a free piece of software and it is provided as is, without any warranty.
There might be functions that need a connection to the internet: '+\n '

By entering a token and/or pressing UPLOAD, the device will create a connection to my servers, where the associated user information is stored (token, email, name, credit, limit_photos, limit_filesize)'+\n 'The selected image set will be uploaded to Dropbox Inc via one-time temporary upload link. The files will be saved on Dropbox Inc. for a maximum of 7 days. (+the time Dropbox Inc. will need to delete the files permanently)'+\n 'Processing will be done on my local servers, where the images get downloaded from Dropbox and processed on my workstations. The resulting 3D model will be uploaded to Dropbox and a link will be created and send to your email address from my google mail account.'+\n '

By uploading data to my servers, you agree, that I can use those images and derived 3d models for further research and to improve my services.'+\n 'The raw images and resulting 3d models will never be published without your explicit consent.'+ \n '

If you have any questions you can contact me at info@openscan.eu.'+ \n '

THE SOFTWARE IS PROVIDED AS IS WITHOUT '+\n 'WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE'+ \n 'AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY,'+ \n 'WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE';\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 300, - "wires": [ - [ - "7dc39bd847d16ded" - ] - ] - }, - { - "id": "5f849178998d9082", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "if(msg.payload === 'Agree'){\n data = true;\n}\nelse{\n data = false;\n}\nvar file = 'terms'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nfs.writeFile(filepath+file, String(data), err => {\n if (err) {\n return msg\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 550, - "y": 300, - "wires": [ - [] - ] - }, - { - "id": "725fd0cab0bddc0e", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'hostname'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = String(data);\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 620, - "wires": [ - [ - "49259adad52fc214" - ] - ] - }, - { - "id": "49259adad52fc214", - "type": "ui_text_input", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Hostname", - "tooltip": "", - "group": "3b4bd36726be16d5", - "order": 13, - "width": 6, - "height": 1, - "passthru": false, - "mode": "text", - "delay": "0", - "topic": "Change hostname to:", - "sendOnBlur": true, - "className": "", - "topicType": "str", - "x": 550, - "y": 620, - "wires": [ - [ - "8001f7c361de7d8c" - ] - ] - }, - { - "id": "51521bc6eb44cde5", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "msg.enabled = false\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 270, - "y": 660, - "wires": [ - [ - "59c9f67283ba1709" - ] - ] - }, - { - "id": "2bb52656f9554dab", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "ssid = msg.payload\nmsg.topic = 'Add wifi network (' + ssid + ')'\nmsg.payload = 'Enter Wifi password:'\nmsg.ssid = ssid\n\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 670, - "y": 660, - "wires": [ - [ - "ebcc98685059b9d4" - ] - ] - }, - { - "id": "ebce67b739d1891f", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "chk/change hostname", - "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n pass\n\nwith open('/etc/hostname', 'r') as file:\n old_hostname = file.read().replace('\\n','')\n\nhostname = msg['hostname']\nif len(hostname) < 4 :\n msg['payload'] = ' '\n msg['topic'] = 'ERROR - Hostname NOT changed'\n return msg\n \n\nwith open('/etc/hostname', 'w+') as file:\n file.write(hostname)\nos.system('echo ' + hostname + ' | sudo tee /etc/hostname')\nwith open('/etc/hosts', 'r') as file:\n temp = file.read()\ntemp = temp.replace(old_hostname,hostname)\nwith open('/etc/hosts', 'w') as file:\n file.write(temp)\nos.system('sudo hostnamectl set-hostname ' + hostname)\nos.system('sudo systemctl restart avahi-daemon')\nsave('hostname',hostname)\nmsg['payload'] = hostname\nmsg['topic'] = 'Success - Hostname changed'\nreturn msg\n", - "outputs": 1, - "x": 1160, - "y": 620, - "wires": [ - [ - "03732a7d3b0c95aa" - ] - ] - }, - { - "id": "667ac2aba819f506", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "Confirm", - "x": 940, - "y": 620, - "wires": [ - [ - "ebce67b739d1891f" - ] - ] - }, - { - "id": "8001f7c361de7d8c", - "type": "change", - "z": "017bd4e4a428bee5", - "name": "", - "rules": [ - { - "t": "set", - "p": "hostname", - "pt": "msg", - "to": "payload", - "tot": "msg" - } - ], - "action": "", - "property": "", - "from": "", - "to": "", - "reg": false, - "x": 730, - "y": 620, - "wires": [ - [ - "667ac2aba819f506" - ] - ] - }, - { - "id": "9bb0adbd716ce347", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "reboot", - "links": [ - "16c76929f88df841", - "fe3a855fee9e28c6", - "d663dd83d71b8693" - ], - "x": 175, - "y": 380, - "wires": [ - [ - "d114f4d4d7f31981", - "cc3cb10f2ea3f8b8" - ] - ] - }, - { - "id": "fc9abb94c35eec56", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "shutdown", - "links": [ - "597bfb653e8cddbf" - ], - "x": 175, - "y": 460, - "wires": [ - [ - "cc3cb10f2ea3f8b8", - "f52d4d86b39aeb6b" - ] - ] - }, - { - "id": "f9efcb87b74abbd4", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "if (msg.payload === 'Cancel'){\n return\n}\nmsg.forename = msg.payload\nmsg.topic = 'OpenScanCloud Registration (3/3)'\nmsg.payload = 'Enter your last name'\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 690, - "y": 960, - "wires": [ - [ - "510dbe4d76253bd6" - ] - ] - }, - { - "id": "adc206aa8edd1e41", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "OSC", - "group": "db43d646.2074c8", - "order": 2, - "width": 3, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Files&Cloud

Refresh

You can refresh the status of the processing of your files in the OpenScanCloud. Make sure to read and agree the terms of use (in settings menu) before using the OpenScanCloud. Do not spam this button, as this might lead to temporary/permanent suspension of your IP address.

The status (in the table) of the individual sets in the file list will be updated to one of the following:

Created - you started the upload of your image set. If you are stuck on this status, please try to restart the upload.

Initialized - all files have been uploaded and processing will start as soon as possible

File approved - the server received and verified your files

Processing started - your files are currently being processed

Processing failed - there are various reasons why processing might fail. Please check the email for more details or contact me at cloud@openscan.eu

processing done - check your email, where you should find a link to the 3d model :)

Status (on the right column)

Indicates, what the device is currently up to.

Refreshing - updating all image set's status

Uploading - while transferring the image set to the OpenScanCloud servers. If the upload freezes, be patient. If nothing happens, reboot the device and restart the upload.

Project started - when the upload of a set was successful

Zipping - files larger then 200mb have to be split and re-zipped before uploading to the OpenScanCloud, the process might take a while depending on the filesize.

Combining - two sets into one might take up to a minute. 

Set

select a set from the file list by clicking on a row in the table

Download

Download the selected set from the OpenScan device to your computer/mobile/tablet

Upload

Upload the selected file to the OpenScanCloud

Combine

In order to combine two sets, select one set. Click the combine button and select the second set. A pop-up will appear, and you can confirm the operation. All images from the two sets will be merged into one set. The original image sets will be deleted!

Delete Set/All

Please keep in mind, that the memory of the SD card is relatively small, and thus you will have to delete individual or all photo sets from time to time.

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 470, - "y": 160, - "wires": [ - [ - "f304680180a23479" - ] - ] - }, - { - "id": "e9677b85856b5873", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "Reset rfkill", - "func": "from os import system\nif \"Interface doesn't support scanning\" in msg['payload']:\n system('rfkill unblock all')\n system('sudo ifconfig wlan0 up')\n return msg", - "outputs": 1, - "x": 410, - "y": 740, - "wires": [ - [] - ] - }, - { - "id": "9b2bc9849aee310b", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "changeHostname", - "links": [ - "ec2db55a99bbe3ee", - "d5175561293ef490", - "960912e90ba5b5bc" - ], - "x": 855, - "y": 580, - "wires": [ - [ - "8b9e3781511e9231" - ] - ] - }, - { - "id": "8b9e3781511e9231", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "chk", - "func": "with open('/etc/hostname', 'r') as file:\n old_hostname = file.read().replace('\\n','')\nif old_hostname == 'raspberrypi':\n msg['hostname'] = 'openscan'\n msg['payload'] = 'OK'\n return msg", - "outputs": 1, - "x": 950, - "y": 580, - "wires": [ - [ - "ebce67b739d1891f" - ] - ] - }, - { - "id": "65b38bfeb3fee710", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 175, - "y": 420, - "wires": [ - [ - "cc3cb10f2ea3f8b8" - ] - ] - }, - { - "id": "d3fc91d87d5d5f62", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 155, - "y": 620, - "wires": [ - [ - "725fd0cab0bddc0e" - ] - ] - }, - { - "id": "cc9c4092edeb43cc", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "enable projectname", - "links": [ - "960912e90ba5b5bc" - ], - "x": 155, - "y": 700, - "wires": [ - [ - "27c6b221c90ed9e1" - ] - ] - }, - { - "id": "80bccc884b0be297", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "38783aea9cc317a6" - ], - "x": 1435, - "y": 300, - "wires": [] - }, - { - "id": "25426d3582cc1236", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Enter Tk", - "group": "3b4bd36726be16d5", - "order": 3, - "width": 2, - "height": 1, - "passthru": false, - "label": "Enter Token", - "tooltip": "testtesttest", - "color": "", - "bgcolor": "", - "className": "", - "icon": "", - "payload": "Please enter your OpenScanCloud Token:", - "payloadType": "str", - "topic": "Token", - "topicType": "str", - "x": 120, - "y": 1060, - "wires": [ - [ - "c690fed61878ce83" - ] - ] - }, - { - "id": "c690fed61878ce83", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "prompt", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "Cancel", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 270, - "y": 1060, - "wires": [ - [ - "781f672b78ea70b2" - ] - ] - }, - { - "id": "781f672b78ea70b2", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "save", - "func": "import requests\nimport os\nfrom OpenScan import save, OpenScanCloud\n\nif msg['payload'] == 'Cancel':\n return\n\ntoken = msg['payload']\n\nif len(msg['payload']) >=14:\n try:\n r = OpenScanCloud('getTokenInfo', {'token':token})\n if r.status_code != 200:\n msg['topic'] = 'Error'\n msg['payload'] = 'Invalid Token'\n return msg \n \n msg1 = r.json()\n save('osc_credit',msg1['credit'])\n save('osc_limit_filesize',msg1['limit_filesize'])\n save('osc_limit_photos',msg1['limit_photos'])\n save('token',token)\n msg['topic'] = 'Success'\n msg['payload'] = 'Token verified and saved'\n except:\n msg['topic'] = 'Error'\n msg['payload'] = 'Could not verify token, please check your internet connection.'\n return msg \n\n\nelse:\n msg['topic'] = 'Error'\n msg['payload'] = 'Invalid tokenformat'\n\nreturn msg", - "outputs": 1, - "x": 430, - "y": 1060, - "wires": [ - [ - "5e4b3bdb0a26052d", - "4faf2fbd3cf6aa3a", - "a7fd00943edc380b" - ] - ] - }, - { - "id": "6d2c65d7e1d928ce", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "order": 6, - "width": 0, - "height": 0, - "name": "", - "label": "Token", - "format": "{{msg.payload}}", - "layout": "row-spread", - "className": "", - "x": 710, - "y": 1100, - "wires": [] - }, - { - "id": "5e4b3bdb0a26052d", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "text", - "func": "from OpenScan import load_str\n\ntoken = load_str('token')[0:8]\nmsg['payload']= token + '...'\nif len(token)==0:\n msg['payload']=\"enter token\"\nreturn msg", - "outputs": 1, - "x": 590, - "y": 1100, - "wires": [ - [ - "6d2c65d7e1d928ce" - ] - ] - }, - { - "id": "e0965e490d53617f", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "token", - "links": [ - "960912e90ba5b5bc" - ], - "x": 465, - "y": 1100, - "wires": [ - [ - "5e4b3bdb0a26052d" - ] - ] - }, - { - "id": "4faf2fbd3cf6aa3a", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 610, - "y": 1060, - "wires": [ - [] - ] - }, - { - "id": "36b3b36c399ac7db", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "get update", - "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", - "outputs": 2, - "x": 310, - "y": 1380, - "wires": [ - [ - "1d9f24f41817a2de" - ], - [ - "0c1d054fa7f2afe8" - ] - ] - }, - { - "id": "48cd023b07c39a94", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "order": 20, - "width": 0, - "height": 0, - "name": "", - "label": "Status:", - "format": "{{msg.status}}", - "layout": "row-spread", - "className": "", - "x": 170, - "y": 1300, - "wires": [] - }, - { - "id": "0c1d054fa7f2afe8", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "check files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\nfrom time import sleep\n\nsleep(1)\n\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter # new file counter\n\nreturn msg\n", - "outputs": 1, - "x": 470, - "y": 1400, - "wires": [ - [ - "1d9f24f41817a2de", - "7097687ddcc4fa8e" - ] - ] - }, - { - "id": "612a7556ab11cf7d", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "", - "links": [ - "960912e90ba5b5bc" - ], - "x": 75, - "y": 1340, - "wires": [ - [ - "e447af84ecc540ad", - "72ca6c281c43acd7", - "dadf823225aa34c4", - "9df2481a03f24d0a" - ] - ] - }, - { - "id": "7097687ddcc4fa8e", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "NO", - "cancel": "YES", - "raw": false, - "className": "", - "topic": "", - "name": "", - "x": 630, - "y": 1420, - "wires": [ - [ - "f9fe26a38501bcad", - "77859c0059f8a49e" - ] - ] - }, - { - "id": "9112e8b2865ea436", - "type": "link in", - "z": "017bd4e4a428bee5", - "name": "update status", - "links": [ - "1d9f24f41817a2de", - "26dae88a383eee97" - ], - "x": 75, - "y": 1300, - "wires": [ - [ - "48cd023b07c39a94" - ] - ] - }, - { - "id": "1d9f24f41817a2de", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "9112e8b2865ea436" - ], - "x": 575, - "y": 1380, - "wires": [] - }, - { - "id": "f9fe26a38501bcad", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "download files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", - "outputs": 1, - "x": 800, - "y": 1440, - "wires": [ - [ - "26dae88a383eee97", - "d663dd83d71b8693" - ] - ] - }, - { - "id": "77859c0059f8a49e", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "msg", - "func": "if (msg.payload == 'YES'){\n msg.status = 'Installing updates'\n return msg}", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 770, - "y": 1400, - "wires": [ - [ - "26dae88a383eee97" - ] - ] - }, - { - "id": "26dae88a383eee97", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "9112e8b2865ea436" - ], - "x": 925, - "y": 1400, - "wires": [] - }, - { - "id": "e447af84ecc540ad", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\n\nmsg.payload = data\n\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 170, - "y": 1380, - "wires": [ - [ - "36b3b36c399ac7db" - ] - ] - }, - { - "id": "d663dd83d71b8693", - "type": "link out", - "z": "017bd4e4a428bee5", - "name": "", - "mode": "link", - "links": [ - "9bb0adbd716ce347" - ], - "x": 925, - "y": 1440, - "wires": [] - }, - { - "id": "444acd32e7578254", - "type": "python3-function", - "z": "017bd4e4a428bee5", - "name": "create beta new", - "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'mini'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\ntry:\n del msg[scope]\nexcept:\n pass\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/Arducam.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/Arducam.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/OpenScan.py'\nmsg[scope]['3']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/config.txt'\nmsg[scope]['4']['dst'] = '/boot/config.txt'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/flows.json'\nmsg[scope]['5']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['6'] = {}\nmsg[scope]['6']['src'] = scope + '/settings.js'\nmsg[scope]['6']['dst'] = '/root/.node-red/settings.js'\n\nmsg[scope]['7'] = {}\nmsg[scope]['7']['src'] = 'files/logo.jpg'\nmsg[scope]['7']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", - "outputs": 1, - "x": 280, - "y": 1780, - "wires": [ - [ - "7f097823a90facb6" - ] - ] - }, - { - "id": "7f097823a90facb6", - "type": "debug", - "z": "017bd4e4a428bee5", - "name": "", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 430, - "y": 1780, - "wires": [] - }, - { - "id": "e547e40ff805742b", - "type": "inject", - "z": "017bd4e4a428bee5", - "name": "", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "", - "payloadType": "date", - "x": 120, - "y": 1780, - "wires": [ - [ - "444acd32e7578254" - ] - ] - }, - { - "id": "5fe2d831c3ab1cf4", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 570, - "y": 1340, - "wires": [ - [] - ] - }, - { - "id": "154716c51aae2b87", - "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Auto-check update availability", - "tooltip": "", - "group": "3b4bd36726be16d5", - "order": 21, - "width": 6, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "", - "topicType": "str", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 370, - "y": 1340, - "wires": [ - [ - "5fe2d831c3ab1cf4" - ] - ] - }, - { - "id": "72ca6c281c43acd7", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'update_auto'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 170, - "y": 1340, - "wires": [ - [ - "154716c51aae2b87" - ] - ] - }, - { - "id": "a0e996cbd2b18363", - "type": "comment", - "z": "017bd4e4a428bee5", - "name": "Updates", - "info": "", - "x": 120, - "y": 1240, - "wires": [] - }, - { - "id": "0dcf979b126c3e33", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "order": 1, - "width": 4, - "height": 1, - "name": "", - "label": "", - "format": "OPENSCANCLOUD", - "layout": "col-center", - "className": "", - "x": 290, - "y": 900, - "wires": [] - }, - { - "id": "50ab351d92165de8", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "order": 9, - "width": 4, - "height": 1, - "name": "", - "label": "", - "format": "NETWORK SETTINGS", - "layout": "col-center", - "className": "", - "x": 270, - "y": 560, - "wires": [] - }, - { - "id": "726819d40397f3ce", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Wifi", - "group": "3b4bd36726be16d5", - "order": 10, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Network Settings

Hostname

The device can be accessed through any browser in the same network. Therefore, you can either enter the device's IP address or the given hostname. The standard name is 'openscan' but it is highly recommended to change the name, when using multiple devices (e.g. 'openscan1', 'openscan2' ...)

Select Wifi

After booting, the device will automatically search for available wireless networks and create a list. You can connect to a given network by entering the wifi password and country code. To find the right two-character country code, see the following list: ISO 3166 Country Code on Wikipedia

Search Wifi

You can manually refresh the list of available networks by pressing this button.

Reset Wifi

Delete the list of known wireless networks (and passwords) and reset the default. After this step, you will either need to use Ethernet or a modified wpa_supplicant.conf file. (see glennklockwood.com for more details about the wpa_supplicant.conf file, which has to be manually created and placed into the /boot/ directory of the sd-card)

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 250, - "y": 160, - "wires": [ - [ - "f304680180a23479" - ] - ] - }, - { - "id": "d07e9c092f0855eb", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "order": 16, - "width": 4, - "height": 1, - "name": "", - "label": "", - "format": "UPDATES", - "layout": "col-center", - "className": "", - "x": 270, - "y": 1240, - "wires": [] - }, - { - "id": "a85de9dee94dc786", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Updates&LOG", - "group": "3b4bd36726be16d5", - "order": 17, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 280, - "y": 200, - "wires": [ - [ - "f304680180a23479" - ] - ] - }, - { - "id": "2968c5996fb6d98c", - "type": "ui_template", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "name": "Download LOG", - "order": 25, - "width": 6, - "height": 1, - "format": "\n
Download error log\n
\n", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 140, - "y": 1520, - "wires": [ - [] - ] - }, - { - "id": "d66c08c5f0134cf3", - "type": "ui_template", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "name": "Check Updates", - "order": 18, - "width": 6, - "height": 1, - "format": "Check updates", - "storeOutMessages": false, - "fwdInMessages": false, - "resendOnRefresh": false, - "templateScope": "local", - "className": "", - "x": 140, - "y": 1420, - "wires": [ - [ - "36b3b36c399ac7db" - ] - ] - }, - { - "id": "f304680180a23479", - "type": "ui_toast", - "z": "017bd4e4a428bee5", - "position": "dialog", - "displayTime": "3", - "highlight": "", - "sendall": true, - "outputs": 1, - "ok": "OK", - "cancel": "", - "raw": true, - "className": "", - "topic": "", - "name": "Info", - "x": 630, - "y": 120, - "wires": [ - [] - ] - }, - { - "id": "955f1e6794f368e2", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Scan", - "group": "7aaf184330605300", - "order": 1, - "width": 6, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Files&Cloud

Current Status

--READY-- - everything is okay and ready to go :)

Routine-preparing - before starting the routine some time might pass depending on the number of photos

Routine-stopping - manually ending the routine by pressing the stop button

Routine-Photo X/Y - Showing the progress of the routine

No Camera Found - please check the camera ribbon cable

Error: XXX - Please contact info@openscan.eu or post an issue on Github.com

Projectname

Each photo set will be saved using the following pattern  YYYY-MM-DD_hh-mm-ss_projectname.zip (e.g. 2022-04-05_12.12.12_toysoldier.zip). Keep your files organized by giving each set a new projectname. If not specified 'default' will be used.

Rotor

Moving the rotor by increments of 5°. Please make sure to start the routine with the camera in the horizontal position.

Turntable

Moving the turntable by increments of 15°.

Ringlight

Use the ring light for shadow-free illumination. It is highly recommended to use the polarizer in order to avoid reflections. Note, that the polarizer will absorb 75% of the light, so you might need to use both ring lights.

Photos

Set the number of photos for the current set. 60-120 photos should be more than enough for most objects. If the reconstruction fails or is very bad with 60 photos, increasing the number of photos will not help!

Shutter

Again: Less is more! If the value is too high, some areas might get overexposed and thus, the software will not be able to recognize the surface feature of the object. Here are some reference values:

- no polarizer: 5-20ms

- mostly white object,  with polarizer + one ringlight: 50-200ms

Crop X/Y

Make sure to use the right object holder to place the object in the middle of the screen. Try to crop as many unnecessary areas as possible. This will greatly lower the file size and resulting transfer and reconstruction times!

Start/Stop

Use the buttons to start/stop the routine

Reboot/Shutdown

In case of an error, try to restart the device. Always use the shutdown button before powering-off the device!

MF - Manual Focus

By default, the switch is 'off', which means that autofocus is active. For small objects, it might be necessary to use manual focus: activate the switch and set the focus by pressing + and - accordingly. The distance is measured between the camera lens and the focal plane (which should be in the center or slightly in front of the center of the object).

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 470, - "y": 200, - "wires": [ - [ - "f304680180a23479" - ] - ] - }, - { - "id": "dadf823225aa34c4", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadB", - "func": "var file = 'turntable_mode'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 170, - "y": 1620, - "wires": [ - [ - "60f6ee795446200d" - ] - ] - }, - { - "id": "60f6ee795446200d", - "type": "ui_switch", - "z": "017bd4e4a428bee5", - "name": "", - "label": "Turntable Mode", - "tooltip": "", - "group": "3b4bd36726be16d5", - "order": 26, - "width": 6, - "height": 1, - "passthru": true, - "decouple": "false", - "topic": "", - "topicType": "str", - "style": "", - "onvalue": "true", - "onvalueType": "bool", - "onicon": "", - "oncolor": "", - "offvalue": "false", - "offvalueType": "bool", - "officon": "", - "offcolor": "", - "animate": false, - "className": "", - "x": 320, - "y": 1620, - "wires": [ - [ - "227d89d897a8bdf5" - ] - ] - }, - { - "id": "227d89d897a8bdf5", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'turntable_mode'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 470, - "y": 1620, - "wires": [ - [] - ] - }, - { - "id": "8b317478e9d905b8", - "type": "ui_button", - "z": "017bd4e4a428bee5", - "name": "Other Settings", - "group": "3b4bd36726be16d5", - "order": 24, - "width": 2, - "height": 1, - "passthru": false, - "label": "", - "tooltip": "", - "color": "", - "bgcolor": "transparent", - "className": "", - "icon": "fa-question-circle", - "payload": "

Network Settings

Hostname

The device can be accessed through any browser in the same network. Therefore, you can either enter the device's IP address or the given hostname. The standard name is 'openscan' but it is highly recommended to change the name, when using multiple devices (e.g. 'openscan1', 'openscan2' ...)

Select Wifi

After booting, the device will automatically search for available wireless networks and create a list. You can connect to a given network by entering the wifi password and country code. To find the right two-character country code, see the following list: ISO 3166 Country Code on Wikipedia

Search Wifi

You can manually refresh the list of available networks by pressing this button.

Reset Wifi

Delete the list of known wireless networks (and passwords) and reset the default. After this step, you will either need to use Ethernet or a modified wpa_supplicant.conf file. (see glennklockwood.com for more details about the wpa_supplicant.conf file, which has to be manually created and placed into the /boot/ directory of the sd-card)

", - "payloadType": "str", - "topic": "topic", - "topicType": "msg", - "x": 280, - "y": 80, - "wires": [ - [] - ] - }, - { - "id": "814eaca62debe694", - "type": "ui_text", - "z": "017bd4e4a428bee5", - "group": "3b4bd36726be16d5", - "order": 23, - "width": 4, - "height": 1, - "name": "", - "label": "", - "format": "OTHER SETTINGS", - "layout": "col-center", - "className": "", - "x": 170, - "y": 1580, - "wires": [] - }, - { - "id": "9df2481a03f24d0a", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "loadS", - "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\n\nmsg.payload = String(data.replace(/(\\r\\n|\\n|\\r)/gm,\"\"));\nreturn msg", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 170, - "y": 1660, - "wires": [ - [ - "ecba1ecce99e3968" - ] - ] - }, - { - "id": "f1de798f2a68e76e", - "type": "function", - "z": "017bd4e4a428bee5", - "name": "write", - "func": "var file = 'update_type'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", - "outputs": 1, - "noerr": 0, - "initialize": "", - "finalize": "", - "libs": [], - "x": 470, - "y": 1660, - "wires": [ - [] - ] - }, - { - "id": "ecba1ecce99e3968", - "type": "ui_dropdown", - "z": "017bd4e4a428bee5", - "name": "Update_select", - "label": "", - "tooltip": "", - "place": "Select version", - "group": "3b4bd36726be16d5", - "order": 19, - "width": 0, - "height": 0, - "passthru": false, - "multiple": false, - "options": [ - { - "label": "Mini_simplified", - "value": "mini", - "type": "str" - }, - { - "label": "Advanced", - "value": "main", - "type": "str" - }, - { - "label": "Beta", - "value": "beta", - "type": "str" - } - ], - "payload": "", - "topic": "topic", - "topicType": "msg", - "className": "", - "x": 320, - "y": 1660, - "wires": [ - [ - "f1de798f2a68e76e" - ] - ] - } -] \ No newline at end of file diff --git a/update/stable/OpenScan.py b/update/stable/OpenScan.py new file mode 100644 index 0000000..681c78d --- /dev/null +++ b/update/stable/OpenScan.py @@ -0,0 +1,316 @@ +basepath = '/home/pi/OpenScan/' +from os.path import isfile +import os + +def load_bool(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + if value == '1' or value == 'True' or value =='true': + value = True + else: + value = False + return value + +def fade_led(pin_led, fade_steps, duty_max, dir = True): + import RPi.GPIO as GPIO + import time + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(pin_led, GPIO.OUT) + pwm = GPIO.PWM(pin_led, 200) + + if dir: + pwm.start(0) + for duty_cycle in range(0, fade_steps*10, 1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + else: + pwm.start(duty_max) + for duty_cycle in range(fade_steps*10,0, -1): # Increase duty cycle in steps + pwm.ChangeDutyCycle(duty_max*duty_cycle/(10*fade_steps)) + time.sleep(0.001) # Pause between steps (adjust as needed) + pwm.stop() + + +def check_hotspot_mode(interface="wlan0"): + import subprocess + try: + output = subprocess.check_output(["iwconfig", interface]).decode("utf-8") + if "Mode:Master" in output: + return True + elif "Mode:Managed" in output: + return False + else: + return False + except subprocess.CalledProcessError as e: + return False + + + +def add_wifi_network(ssid, password, country): + import re + conf_file = "/etc/wpa_supplicant/wpa_supplicant-wlan0.conf" + + if not os.path.exists(conf_file): + return False + + if not (ssid and password and country): + return False + + with open(conf_file, "r") as f: + content = f.read() + + updated_content = re.sub(r'country=\w+', f'country={country}', content) + + if f'ssid="{ssid}"' in content: + network_block_pattern = re.compile( + r'network=\{\s*ssid="' + re.escape(ssid) + r'".*?psk=".*?".*?\}', re.DOTALL + ) + updated_network_block = f'network={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}' + updated_content = network_block_pattern.sub(updated_network_block, updated_content) + else: + network_block = f'\nnetwork={{\n ssid="{ssid}"\n psk="{password}"\n key_mgmt=WPA-PSK\n}}\n' + updated_content += network_block + + with open(conf_file, "w") as f: + f.write(updated_content) + os.system("sudo systemctl restart wpa_supplicant@wlan0") + + return True + + +def load_str(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = file.read().replace('\n','') + return value + +def load_int(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = int(file.read().replace('\n','')) + return value + +def load_float(name): + filename = basepath+'settings/'+name + if not isfile(filename): + return + with open(filename, 'r') as file: + value = float(file.read().replace('\n','')) + return value + +def save(name, value): + filename = basepath+'settings/'+name + with open(filename, 'w+') as file: + file.write(str(value)) + return + +def OpenScanCloud(cmd, msg): + from requests import get + osc_user = 'openscan' + osc_pw = 'free' + osc_server = 'http://openscanfeedback.dnsuser.de:1334/' + + try: + r = get(osc_server + cmd, auth=(osc_user, osc_pw), params=msg) + except: + r = type('obj', (object,), {'status_code' : 404, 'text':None}) + return r + +def camera(cmd, msg = {}): + from requests import get + flask = 'http://127.0.0.1:1312/' + try: + r = get(flask + cmd, params=msg) + return r.status_code + except: + return 400 + +def motorrun(motor,angle,ES_enable=False,ES_start_state = True): + #motor can be "rotor", "tt" or "extra" + import RPi.GPIO as GPIO + from time import sleep + from math import cos + msg = {'cmd':'set'} + + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + + spr = load_int(motor + '_stepsperrotation') + dirpin = load_int('pin_' + motor + '_dir') + steppin = load_int('pin_' + motor +'_step') + ES_pin = load_int('pin_' + motor + '_endstop') + dir = load_int(motor + '_dir') + ramp = load_int(motor + '_accramp') + acc = load_float(motor + '_acc') + delay_init = load_float(motor + '_delay') + delay = delay_init + + step_count=int(angle*spr/360) * dir + GPIO.setup(dirpin, GPIO.OUT) + GPIO.setup(steppin, GPIO.OUT) + GPIO.setup(ES_pin, GPIO.IN, pull_up_down = GPIO.PUD_UP) + + if (step_count>0): + GPIO.output(dirpin, GPIO.HIGH) + if(step_count<0): + GPIO.output(dirpin, GPIO.LOW) + step_count=-step_count + for x in range(step_count): + if ES_enable == True and GPIO.input(ES_pin) != ES_start_state: + i = 0 + while i <= 10: + if GPIO.input(ES_pin) == ES_start_state: + i = 11 + if i == 10: + return + i = i + 1 + + GPIO.output(steppin, GPIO.HIGH) + if x<=ramp and x<=step_count/2: + delay = delay_init * (1 + -1/acc*cos(1*(ramp-x)/ramp)+1/acc) + #delay=delay_init+(ramp-x)*(delay_init)/acc + elif step_count-x<=ramp and x>step_count/2: + delay = delay_init * (1-1/acc*cos(1*(ramp+x-step_count)/ramp)+1/acc) + #delay=delay_init+(ramp-step_count+x)*(delay_init)/acc + else: + delay = delay_init + sleep(delay) + GPIO.output(steppin, GPIO.LOW) + sleep(delay) + +def ringlight(number,state): + import RPi.GPIO as GPIO + msg = {'cmd':'set'} + pin = load_int('pin_ringlight' + str(number)) + GPIO.setwarnings(False) + GPIO.setmode(GPIO.BCM) + GPIO.setup(pin, GPIO.OUT) + GPIO.output(pin, state) + +def take_photo(file): + from os import system + filepath = basepath + file + + model=load_str('model') + + + + shutter = str(load_int('cam_shutter')) + saturation = load_str('cam_saturation') + contrast = load_str('cam_contrast') + awbg_red = load_str('cam_awbg_red') + awbg_blue = load_str('cam_awbg_blue') + gain = load_str('cam_gain') + quality = load_int('cam_jpeg_quality') + filepath2 = '/home/pi/OpenScan/tmp/tmp.jpg' + #width = load_str('cam_resx') + #height = load_str('cam_resy') + timeout = load_str('cam_timeout') + cropx = load_int('cam_cropx')/200 + cropy = load_int('cam_cropy')/200 + rotation = load_int('cam_rotation') + AF = load_bool('cam_AFmode') + camera = load_str('camera') + + + if camera == 'imx519' and AF == True: + autofocus = ' --autofocus ' + else: + autofocus = '' + + if camera == "usb_webcam": + cmd = 'fswebcam -i 0 -r "1280x720" -F 5 --no-banner --jpeg 95 --save ' + filepath2 + else: + cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + ' >/dev/null 2>&1' + # cmd = 'libcamera-still -n --denoise off --sharpness 0 -o ' + filepath2 + ' -t ' + timeout +' --shutter ' + shutter + ' --saturation ' + saturation + ' --contrast ' + contrast + ' --awbgains '+awbg_red + "," + awbg_blue + ' --gain ' + gain + ' -q ' + str(quality) + autofocus + + system(cmd) + return cmd + +def get_points(samples=1): + from math import pi, sqrt, acos, atan2, cos, sin + + points = [] + phi = pi * (3. - sqrt(5.)) + for i in range(int(samples)): + y = 1 - (i / float(samples - 1)) * 2 + radius = sqrt(1 - y * y) + theta = phi * i + x = cos(theta) * radius + z = sin(theta) * radius + r=sqrt(x*x+y*y+z*z) + theta_neu=acos(z/r)*180/pi + phi_neu=atan2(y,x)*180/pi + points.append((theta_neu-90,phi_neu)) + points.sort() + return points + +def create_coordinates(angle_min, angle_max,point_count): + point_count_final=point_count + if angle_max < angle_min: + a = angle_min + angle_min = angle_max + angle_max = a + point_count=point_count*90/(angle_max-angle_min) + actual_points=0 + while actual_pointsangle_min and x20: + point_count=point_count+3 + else: + point_count=point_count+1 + return filtered + + +def haversine_distance_deg(theta1, phi1, theta2, phi2): + import numpy as np + R = 1 + dtheta = np.radians(theta2 - theta1) + dphi = np.radians(phi2 - phi1) + + theta1, phi1 = np.radians(theta1), np.radians(phi1) + theta2, phi2 = np.radians(theta2), np.radians(phi2) + + a = np.sin(dtheta / 2) ** 2 + np.cos(theta1) * np.cos(theta2) * np.sin(dphi / 2) ** 2 + c = 2 * np.arctan2(np.sqrt(a), np.sqrt(1 - a)) + + return R * c + +def sort_spherical_coordinates_deg(points_spherical_deg): + import numpy as np + from tsp_solver.greedy import solve_tsp + + points_spherical_deg = np.array(points_spherical_deg) # Convert list of tuples to NumPy array + + n = len(points_spherical_deg) + dist_matrix = np.zeros((n, n)) + + # Calculate haversine distance for each pair of points + for i in range(n): + for j in range(i + 1, n): + dist = haversine_distance_deg(points_spherical_deg[i, 0], points_spherical_deg[i, 1], + points_spherical_deg[j, 0], points_spherical_deg[j, 1]) + dist_matrix[i, j] = dist + dist_matrix[j, i] = dist + + # Solve the TSP problem using the tsp_solver.greedy algorithm + path = solve_tsp(dist_matrix) + + sorted_points_spherical_deg = points_spherical_deg[path] + + # Convert the sorted NumPy array back to a list of tuples + return [tuple(point) for point in sorted_points_spherical_deg] diff --git a/update/betaArdu/config.txt b/update/stable/config.txt old mode 100644 new mode 100755 similarity index 100% rename from update/betaArdu/config.txt rename to update/stable/config.txt diff --git a/update/stable/fla.py b/update/stable/fla.py new file mode 100644 index 0000000..57f4660 --- /dev/null +++ b/update/stable/fla.py @@ -0,0 +1,351 @@ +from flask import Flask, make_response, jsonify, request, abort, redirect +from picamera2 import Picamera2 +from PIL import Image, ImageDraw, ImageOps, ImageFilter, ImageEnhance, ImageChops, ImageFont +from time import sleep, time +import shutil +from OpenScan import load_int, load_float, load_bool, ringlight +import RPi.GPIO as GPIO +from math import sqrt +import os +import math +from skimage import io, feature, color, transform +import numpy as np +from scipy import ndimage +import socket + +GPIO.setwarnings(False) +GPIO.setmode(GPIO.BCM) + +app = Flask(__name__) + +basedir = '/home/pi/OpenScan/' +timer = time() +cam_mode = 0 +hostname = socket.gethostname().split(":") + +def overlay_mask(image, mask_image): + # Ensure image is in RGB mode + image_rgb = image.convert('RGB') + # Create an empty image with RGBA channels + overlay = Image.new('RGBA', image_rgb.size) + + # Prepare a red image of the same size + red_image = Image.new('RGB', image_rgb.size, (255, 0, 0)) + # Prepare a mask where the condition is met (mask_image pixels == 255) + mask_condition = np.array(mask_image) > 0 + overlay_mask = Image.fromarray(np.uint8(mask_condition) * 255) + # Paste the red image onto the overlay using the condition mask + overlay.paste(red_image, mask=overlay_mask) + # Combine the original image with the overlay + combined = Image.alpha_composite(image_rgb.convert('RGBA'), overlay) + # Convert the final image to RGB + combined_rgb = combined.convert('RGB') + return combined_rgb + + + +def highlight_sharpest_areas(image, threshold=load_int('cam_sharpness'), dilation_size=5): + # Convert PIL image to grayscale + image_gray = image.convert('L') + + # Convert grayscale image to numpy array + image_array = np.array(image_gray) + + # Calculate the gradient using a Sobel filter + dx = ndimage.sobel(image_array, 0) # horizontal derivative + dy = ndimage.sobel(image_array, 1) # vertical derivative + mag = np.hypot(dx, dy) # magnitude + + # Threshold the gradient to create a mask of the sharpest areas + mask = np.where(mag > threshold, 255, 0).astype(np.uint8) + + dilated_mask = ndimage.binary_dilation(mask, structure=np.ones((dilation_size,dilation_size))) + # Create a PIL image from the mask + mask_image = Image.fromarray(dilated_mask) + + return mask_image + + + + +################################################################################################################### +@app.route('/shutdown', methods=['get']) +def shutdown(): + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + f = open("/home/pi/OpenScan/settings/session_token", "r") + session_token = (f.readline())[:20] + if shutdown_token == session_token: + + delay = 0.1 + ringlight(2,False) + + for i in range (5): + ringlight(1,True) + sleep(delay) + ringlight(1,False) + sleep(delay) + os.system('shutdown -h now') + + else: + return redirect("http://" + hostname, code=302) +################################################################################################################### +@app.route('/reboot', methods=['get']) +def reboot(): + shutdown_token = request.args.get('token') + hostname = request.host.split(":")[0] + f = open("/home/pi/OpenScan/settings/session_token", "r") + session_token = (f.readline())[:20] + if shutdown_token == session_token: + delay = 0.1 + ringlight(2,False) + + for i in range (5): + ringlight(1,True) + sleep(delay) + ringlight(1,False) + sleep(delay) + + os.system('reboot -h') + else: + return redirect("http://" + hostname, code=302) +################################################################################################################### + +def plot_orb_keypoints(pil_image): + downscale = 2 + # Read the image from the given image path + image = np.array(pil_image) + #image = io.imread(image_path) + image = transform.resize(image, (image.shape[0] // downscale, image.shape[1] // downscale), anti_aliasing=True) + + # Convert the image to grayscale + gray_image = color.rgb2gray(image) + + try: + orb = feature.ORB(n_keypoints=10000, downscale=1.2, fast_n=2, fast_threshold=0.2 , n_scales=3, harris_k=0.001) + orb.detect_and_extract(gray_image) + keypoints = orb.keypoints + except: + return pil_image + + # Convert the image back to the range [0, 255] + display_image = (image * 255).astype(np.uint8) + + # Draw the keypoints on the image + draw = ImageDraw.Draw(pil_image) + size = max(2,int(image.shape[0]*downscale*0.005)) + for i, (y, x) in enumerate(keypoints): + draw.ellipse([(downscale*x-size, downscale*y-size), (downscale*x+size, downscale*y+size)], fill = (0,255,0)) + # Save the image with keypoints to the given output path + return pil_image + +def add_histo(img): + histo_size = 241 + + img_gray = ImageOps.grayscale(img) + histogram = img_gray.histogram() + histogram_log = [math.log10(h + 1) for h in histogram] + histogram_max = max(histogram_log) + histogram_normalized = [float(h) / histogram_max for h in histogram_log] + hist_image = Image.new("RGBA", (histo_size, histo_size), (255, 255, 255, 0)) + draw = ImageDraw.Draw(hist_image) + + for i in range(0, 256): + x = i + y = 256 - int(histogram_normalized[i] * 256) + draw.line((x, 256, x, y), fill=(0, 0, 0, 255)) + + text = "" + if min(histogram[235:238])>0: + text = "overexposed" + if sum(histogram[190:192])<8: + text = "underexposed" + font = ImageFont.truetype("DejaVuSans.ttf", 30) + + bbox = draw.textbbox((0, 0), text, font=font) + + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + + + x = (hist_image.width - text_width )/2 + y = hist_image.height - text_height - 10 + draw.text((x, y), text, font=font, fill=(255,0,0)) + + scale = 0.25 + width1, height1 = hist_image.size + width2 = img.size[0] + new_width1 = int(width2 * scale) + new_height1 = int((height1 / width1) * new_width1) + hist_image = hist_image.convert('RGB') + + hist_image = hist_image.resize((new_width1, new_height1)) + x = hist_image.width - text_width - 10 + y = hist_image.height - text_height - 10 + + + img.paste(hist_image, (img.size[0]-new_width1-int(0.01*img.size[0]),img.size[1]-new_height1-int(0.01*img.size[0]))) + + return img + +def create_mask(image: Image, scale: float = 0.1, threshold: int = 45) -> Image: + threshold = load_int("cam_mask_threshold") + if threshold <= 1: + return image + orig = image + image = image.resize((int(image.width*scale),int(image.height*scale))) + image = image.convert("L") + reduced = image + image = image.filter(ImageFilter.EDGE_ENHANCE) + image = image.filter(ImageFilter.BLUR) + reduced = reduced.filter(ImageFilter.EDGE_ENHANCE_MORE) + mask = ImageChops.difference(image, reduced) + mask = ImageEnhance.Brightness(mask).enhance(2.5) + mask = mask.filter(ImageFilter.MaxFilter(9)) + mask = mask.filter(ImageFilter.MinFilter(5)) + mask = mask.point(lambda x: 255 if x wrong aspect ratio! +# preview_config = picam2.create_preview_configuration(main={"size": (2028, 1520)}) + preview_config = picam2.create_preview_configuration(main={"size": (2028, 1520)}, controls ={"FrameDurationLimits": (1, 1000000)}) + +# preview_config = picam2.create_preview_configuration(main={"size": (2328, 1748)}) + capture_config = picam2.create_still_configuration(controls ={"FrameDurationLimits": (1, 1000000)}) + picam2.configure(preview_config) + picam2.controls.AnalogueGain = 1.0 + picam2.start() + return ({}, 200) + +################################################################################################################### +@app.route('/picam2_take_photo', methods=['get']) +def picam2_take_photo(): + starttime = time() + + cropx = load_int('cam_cropx')/200 + cropy = load_int('cam_cropy')/200 + rotation = load_int('cam_rotation') + img = picam2.capture_image() + + if cam_mode !=1: + img = img.convert('RGB') + w,h = img.size + + if cropx != 0 or cropy != 0: + img = img.crop((w*cropx, h*cropy, w * (1-cropx), h * (1-cropy))) + + if rotation == 90: + img = img.transpose(Image.ROTATE_90) + elif rotation == 180: + img= img.transpose(Image.ROTATE_180) + elif rotation == 270: + img= img.transpose(Image.ROTATE_270) + + if load_bool("cam_mask"): + if cam_mode == 1: + downscale = 0.045*1.4 + else: + downscale = 0.1*1.4 + img = create_mask(img, downscale) + + if load_bool("cam_features") and not load_bool("cam_sharparea"): + img = plot_orb_keypoints(img) + + if load_bool("cam_sharparea") and not load_bool("cam_features"): + img2 = highlight_sharpest_areas(img) + img = overlay_mask(img, img2) + + if cam_mode != 1 and not load_bool("cam_sharparea") and not load_bool("cam_features"): + img = add_histo(img) + + img.save("/home/pi/OpenScan/tmp2/preview.jpg", quality=load_int('cam_jpeg_quality')) + print("total " + str(int(1000*(time()-starttime))) + "ms") + starttime = time() + + return ({}, 200) +################################################################################################################### +@app.route('/picam2_focus', methods=['get']) +def picam2_focus(): + focus = float(request.args.get('focus')) + picam2.set_controls({"AfMode": 0, "LensPosition": focus}) + return ({}, 200) +################################################################################################################### +@app.route('/picam2_af1', methods=['get']) +def picam2_af1(): + from libcamera import controls + + picam2.set_controls({"AfMode": 2 ,"AfTrigger": 0, "AfRange":controls.AfRangeEnum.Macro}) + return ({}, 200) +################################################################################################################### +@app.route('/picam2_af2', methods=['get']) +def picam2_af2(): + picam2.set_controls({"AfMode": 2 ,"AfTrigger": 0}) + return ({}, 200) + +################################################################################################################### +@app.route('/picam2_exposure', methods=['get']) +def picam2_exposure(): + exposure = int(request.args.get('exposure')) + picam2.controls.AnalogueGain = 1.0 + picam2.controls.ExposureTime = exposure + return ({}, 200) +################################################################################################################### +@app.route('/picam2_contrast', methods=['get']) +def picam2_contrast(): + contrast = float(request.args.get('contrast')) + picam2.controls.Contrast = contrast + return ({}, 200) +################################################################################################################### +@app.route('/picam2_saturation', methods=['get']) +def picam2_saturation(): + saturation = float(request.args.get('saturation')) + picam2.controls.Saturation = saturation + return ({}, 200) +################################################################################################################### +@app.route('/picam2_switch_mode', methods=['get']) +def picam2_switch_mode(): + global cam_mode + cam_mode = int(request.args.get('mode')) + if cam_mode == 1: + picam2.switch_mode(capture_config) + else: + picam2.switch_mode(preview_config) + return ({}, 200) +################################################################################################################### +@app.route('/picam2_show_mode', methods=['get']) +def picam2_show_mode(): + global cam_mode + return({"mode":cam_mode},200) +################################################################################################################### +@app.route('/picam2_af', methods=['get']) +def picam2_af(): + picam2.set_controls({"AfMode": 1 ,"AfTrigger": 0}) # --> wait 3-5s + return ({}, 200) + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory(os.path.join(app.root_path, 'static'), + 'favicon.ico', mimetype='image/vnd.microsoft.icon') + +if __name__ == '__main__': +# app.run(host='127.0.0.1', port=1312, debug=False, threaded=True) + app.run(host='0.0.0.0', port=1312, debug=False, threaded=True) diff --git a/update/betaArdu/flows.json b/update/stable/flows.json.tmpl similarity index 89% rename from update/betaArdu/flows.json rename to update/stable/flows.json.tmpl index dc5f6a4..d2e3f3c 100644 --- a/update/betaArdu/flows.json +++ b/update/stable/flows.json.tmpl @@ -364,9 +364,29 @@ "hidden": false }, { - "id": "c82a5d8ffa9290d7", + "id": "6e339d87c7d5debe", "type": "ui_spacer", - "z": "481edaf6db5a7a54", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 1, + "width": 1, + "height": 1 + }, + { + "id": "33b6d7317d1524b8", + "type": "ui_spacer", + "z": "e43a27722b508115", + "name": "spacer", + "group": "db43d646.2074c8", + "order": 3, + "width": 1, + "height": 1 + }, + { + "id": "aaf5b874c52a58aa", + "type": "ui_spacer", + "z": "e43a27722b508115", "name": "spacer", "group": "365a30d0dfa83e95", "order": 8, @@ -374,9 +394,9 @@ "height": 1 }, { - "id": "1234e5ed37d97dbc", + "id": "2e08d4415665c939", "type": "ui_spacer", - "z": "481edaf6db5a7a54", + "z": "e43a27722b508115", "name": "spacer", "group": "365a30d0dfa83e95", "order": 9, @@ -384,9 +404,9 @@ "height": 1 }, { - "id": "0866b0ae68867006", + "id": "f8d8740dcbf499fb", "type": "ui_spacer", - "z": "481edaf6db5a7a54", + "z": "e43a27722b508115", "name": "spacer", "group": "365a30d0dfa83e95", "order": 11, @@ -394,9 +414,9 @@ "height": 1 }, { - "id": "e871dfbac232f86e", + "id": "7ac0cb556740d159", "type": "ui_spacer", - "z": "481edaf6db5a7a54", + "z": "e43a27722b508115", "name": "spacer", "group": "365a30d0dfa83e95", "order": 13, @@ -404,9 +424,9 @@ "height": 1 }, { - "id": "148d18b0fe8c75ea", + "id": "4de2414e29020c74", "type": "ui_spacer", - "z": "481edaf6db5a7a54", + "z": "e43a27722b508115", "name": "spacer", "group": "90223f7ddc082321", "order": 2, @@ -414,9 +434,9 @@ "height": 1 }, { - "id": "acec03936a857704", + "id": "ac8c60543cb04139", "type": "ui_spacer", - "z": "481edaf6db5a7a54", + "z": "e43a27722b508115", "name": "spacer", "group": "ac7409105cfecac6", "order": 3, @@ -424,44 +444,45 @@ "height": 1 }, { - "id": "6e339d87c7d5debe", + "id": "ce21673092264c38", "type": "ui_spacer", "z": "e43a27722b508115", "name": "spacer", - "group": "db43d646.2074c8", - "order": 1, - "width": 1, + "group": "8ab79a98e536e0d6", + "order": 3, + "width": 6, "height": 1 }, { - "id": "33b6d7317d1524b8", + "id": "3f7b77f8a1675d27", "type": "ui_spacer", "z": "e43a27722b508115", "name": "spacer", - "group": "db43d646.2074c8", - "order": 3, - "width": 1, + "group": "12b719cba49817c9", + "order": 7, + "width": 4, "height": 1 }, { - "id": "bd749f72a1b5436c", + "id": "0799b02d12fc3a14", "type": "ui_spacer", "z": "e43a27722b508115", "name": "spacer", - "group": "8ab79a98e536e0d6", - "order": 3, + "group": "7a3279eea439bcdd", + "order": 25, "width": 6, "height": 1 }, { - "id": "61fa5f50a63f5bdd", - "type": "ui_spacer", - "z": "e43a27722b508115", - "name": "spacer", - "group": "12b719cba49817c9", + "id": "220493325bb79987", + "type": "ui_group", + "name": "Messaging", + "tab": "457102eadc9ddb6c", "order": 7, - "width": 4, - "height": 1 + "disp": true, + "width": "6", + "collapse": false, + "className": "" }, { "id": "bc4e2c03859196c3", @@ -549,7 +570,7 @@ "type": "function", "z": "e6f4d02efb300ea9", "name": "CREATE FACTORY DEFAULT", - "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", + "func": "msg = { \n'overwrite':msg.overwrite,\n'settings':\n {\n 'advanced_settings':false,\n 'cam_awbg_blue':0,\n 'cam_awbg_red':0,\n 'cam_contrast':1,\n 'cam_cropx':0,\n 'cam_cropy':0,\n 'cam_delay_after':0,\n 'cam_delay_before':0,\n 'camera':'',\n 'cam_features' : false,\n 'cam_focus_min': 11.5,\n 'cam_focus_max': 11.5,\n 'cam_gain':1,\n 'cam_jpeg_quality':95,\n 'cam_rotation':270,\n 'cam_saturation':1,\n 'cam_stacksize':1,\n 'cam_shutter':50000,\n 'cam_timeout':800,\n 'cam_mask_threshold':45,\n 'cam_mask':true,\n 'hostname':'openscan',\n 'model':'',\n 'osc_credit':'',\n 'osc_limit_filesize':'',\n 'osc_limit_photos':'',\n 'osc_splitsize':200000000,\n// 'pin_extra_endstop': 19,\n 'pin_external': 25,\n 'pin_ringlight1': 24,\n 'pin_ringlight2': 24,\n \n 'pin_rotor_endstop': 17,\n 'pin_rotor_dir': 23,\n 'pin_rotor_enable': 22,\n 'pin_rotor_step': 27,\n 'rotor_acc': 0.5,\n 'rotor_accramp': 500,\n 'rotor_angle': 10,\n 'rotor_anglemax': 75,\n 'rotor_anglemin': -25,\n 'rotor_anglestart': 25,\n 'rotor_delay': 0.0002,\n 'rotor_dir': 1,\n 'rotor_stepsperrotation': 35200/2,\n 'rotor_endstop_angle': 0,\n 'rotor_endstop_enable': false,\n\n // 'pin_tt_endstop': 25,\n 'pin_tt_dir': 6,\n 'pin_tt_enable': 22,\n 'pin_tt_step': 16,\n 'tt_acc': 1,\n 'tt_accramp': 200,\n 'tt_angle': 90,\n 'tt_delay': 0.0001,\n 'tt_dir': 1,\n 'tt_stepsperrotation': 1600,\n\n 'pin_extra_dir': 21,\n 'pin_extra_step': 20,\n 'pin_extra_enable': 22,\n 'extra_acc': 1,\n 'extra_accramp': 200,\n 'extra_angle': 10,\n 'extra_delay': 0.0001,\n 'extra_dir': 1,\n 'extra_stepsperrotation': 3200,\n\n 'routine_photocount':50,\n 'routine_projectname':'default',\n 'smb':true,\n 'ssh':true,\n 'status_cloud':'ready',\n 'status_internal_cam':'--READY--',\n 'status_uploadprogress':'',\n 'terms':false,\n 'token':'',\n\n 'uploadprogress':'',\n 'update_type':'beta',\n 'update_auto':true,\n 'turntable_mode':false,\n 'diskspace_threshold':4000,\n 'updateable':false,\n 'cam_focuspeak':false,\n 'cam_histogram':false,\n 'routine_secondpass':true,\n 'cam_output_resolution':20000000,\n 'cam_preview_resolution':2000000,\n 'cam_output_downscale':false,\n 'cam_sharparea':false,\n 'cam_sharpness':100,\n}}\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", @@ -614,7 +635,8 @@ "592ec13d8f8923a9", "cb40b9341bd22a28", "d1efcd5fa9d25785", - "da61581182b7299e" + "da61581182b7299e", + "2afb6a45c73fa244" ], "x": 645, "y": 60, @@ -808,7 +830,7 @@ "order": 14, "width": 7, "height": 1, - "format": "\n", + "format": "\n", "storeOutMessages": true, "fwdInMessages": true, "resendOnRefresh": true, @@ -1094,7 +1116,8 @@ "592ec13d8f8923a9", "cb40b9341bd22a28", "d1efcd5fa9d25785", - "da61581182b7299e" + "da61581182b7299e", + "2afb6a45c73fa244" ], "x": 1015, "y": 540, @@ -1105,7 +1128,7 @@ "type": "python3-function", "z": "e6f4d02efb300ea9", "name": "motor run", - "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',100,True)\n\nmotorrun('tt',360,True)\nmotorrun('extra',360,True)", + "func": "from OpenScan import motorrun, load_int\nfrom time import sleep\n\nmotorrun('rotor',300,True,False)\n\n", "outputs": 1, "x": 860, "y": 580, @@ -1157,7 +1180,7 @@ "resendOnRefresh": true, "templateScope": "local", "className": "", - "x": 600, + "x": 580, "y": 260, "wires": [ [] @@ -1452,8 +1475,7 @@ "d1b87196ae5373ed", "41e6a4649b6afbfb", "2fd24f8e8e9c08b7", - "85a268108250ba88", - "e78235c36be29dbf" + "85a268108250ba88" ] ] }, @@ -1576,21 +1598,6 @@ ] ] }, - { - "id": "2c58a1a66c4a8c11", - "type": "link in", - "z": "481edaf6db5a7a54", - "name": "preview", - "links": [ - "f20da2fc4978b7bf", - "296636b7467fc745" - ], - "x": 145, - "y": 800, - "wires": [ - [] - ] - }, { "id": "296636b7467fc745", "type": "link out", @@ -2122,7 +2129,7 @@ "initialize": "", "finalize": "", "libs": [], - "x": 300, + "x": 280, "y": 1000, "wires": [ [ @@ -2135,13 +2142,14 @@ "type": "python3-function", "z": "481edaf6db5a7a54", "name": "Routine", - "func": "from OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom time import sleep, strftime, time\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system\nfrom os.path import isfile\nimport math\nimport threading\nimport numpy as np\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\n#motorrun('rotor', 140, ES_enable=True, ES_start_state=True)\n#motorrun('rotor', 10)\n\n\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/picam2_switch_mode?mode=1')\n\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\n\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nangle_start = load_int('rotor_anglestart')\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['payload'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\n\n#for i in range (36):\n# coordinates.append((-25,10*i))\n\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\n#coordinates = [[45,0],[0,0],[-10,0]]\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nstarttime = time()\n\ndef photo(counter2):\n camera('/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef photo_stack():\n c2 = 0\n for f in focuslist:\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(c2+1))\n camera('/picam2_take_photo')\n camera('/picam2_focus?focus=' + str(f)) \n sleep(0.1)\n zip.write(temppath, projectname + '_' + str(counter) + \"-\" + str(c2) + \".jpg\")\n c2 += 1\n\ndef move_motor():\n sleep(1.5 * load_int('cam_shutter') / 1000000)\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n\n motorrun('tt',tt_angle)\n motorrun('rotor',rotor_angle)\n return\n\n # THE FOLLOWING DOES NOT WORK PROPERLY WITH THREADING ?!\n\n tt_thread = threading.Thread(target=motorrun, args=('tt', tt_angle))\n rotor_thread = threading.Thread(target=motorrun, args=('rotor', rotor_angle))\n tt_thread.start()\n rotor_thread.start()\n tt_thread.join()\n rotor_thread.join()\n\n\ncounter2 = 0\n\n\ndef focus(i):\n f = focuslist[i]\n camera('/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\n\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n \n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo_thread = threading.Thread(target=photo, args=(returning,))\n photo_thread.start()\n\n motor_thread = threading.Thread(target=move_motor)\n motor_thread.start()\n photo_thread.join()\n motor_thread.join()\n counter2 = returning[0]\n\n else:\n photo_stack()\n move_motor()\n \n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n position_last = position\n\nzip.close()\ncamera('/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\n\nsystem('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nreturn msg\n", + "func": "from OpenScan import load_bool, load_str, load_int, load_float, motorrun, sort_spherical_coordinates_deg, create_coordinates, take_photo, save, \\\n load_bool, camera\nfrom time import sleep, strftime, time\nfrom subprocess import getoutput, run\n\nfrom zipfile import ZipFile, ZIP_DEFLATED\nfrom os import system, uname\nfrom os.path import isfile, getsize\nimport math\nimport threading\nimport numpy as np\n\nif load_str(\"status_internal_cam\") == \"no camera found\" or load_str(\"status_internal_cam\")[:5] == \"Featu\":\n return\n\n#motorrun('rotor', 140, ES_enable=True, ES_start_state=True)\n#motorrun('rotor', 10)\n\n\n\nsave('status_internal_cam', 'Routine-preparing')\ncamera('/picam2_switch_mode?mode=1')\n\nsave('cam_sharparea', False)\nsave('cam_features', False)\n\n\nprojectname = load_str(\"routine_projectname\")\nangle_max = load_int('rotor_anglemax')\nangle_min = load_int('rotor_anglemin')\nif load_bool('rotor_enable_endstop'):\n angle_start = load_int('rotor_endstop_angle')\n motorrun('rotor',angle_start/abs(angle_start) * 130, True, False)\n\nelse:\n angle_start = load_int('rotor_anglestart')\n\n\nphotocount = load_int('routine_photocount')\n\nfocus_min = load_float('cam_focus_min')\nfocus_max = load_float('cam_focus_max')\nstacksize = load_int('cam_stacksize')\ngroup_stack_photos = load_bool('group_stack_photos')\n\ntelegram_enable = load_bool('telegram_enable')\nif telegram_enable:\n telegram_api_token = load_str('telegram_api_token')\n telegram_client_id = load_str('telegram_client_id')\n\nif focus_min == focus_max:\n stacksize = 1\n\nfocuslist = []\nif stacksize == 1:\n steps = 3 + int(abs(focus_max-focus_min)*0.8)\nelse:\n steps = stacksize\n\nfor i in range (steps):\n focuslist.append(min(focus_min,focus_max) + i * abs(focus_max-focus_min)/(steps-1))\n\nmsg['focuslist'] = focuslist\nmsg['payload2'] = []\ncounter = 0\n\nbasepath = '/home/pi/OpenScan/'\ntemppath = basepath + 'tmp2/preview.jpg'\nzippath = basepath + 'tmp.zip'\n\nprojectcode = strftime('20%y-%m-%d_%H.%M.%S-') + projectname\n\nif isfile(zippath):\n system('rm ' + zippath)\nsleep(1)\n\ncoordinates = create_coordinates(angle_min, angle_max, photocount)\ncoordinates = sort_spherical_coordinates_deg(coordinates)\n\nmsg['payload'] = coordinates\n\nposition_last = (angle_start, 0)\n\nzip = ZipFile(zippath, \"a\", ZIP_DEFLATED, allowZip64=True)\n\nhostname = str(uname()[1])\n\nstarttime = time()\n\ndef get_eta(starttime, photocounter, count):\n return str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n\ndef photo(counter2):\n camera('/picam2_take_photo')\n returning[0] = focus(returning[0])\n zip.write(temppath, projectname + '_' + str(counter) + \".jpg\")\n\ndef stack_photo(i):\n \n camera('/picam2_take_photo')\n if group_stack_photos:\n name = projectname + '_' + str(counter) + \"/\" + projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n else:\n name = projectname + '_' + str(counter) + '-' + str(i) + '.jpg'\n zip.write(temppath, name)\n \ndef stack_focus(i):\n sleep(load_float('cam_shutter')/1000000*2)\n if i < len(focuslist)-1:\n camera('/picam2_focus?focus=' + str(focuslist[i+1]))\n else:\n camera('/picam2_focus?focus=' + str(focuslist[0]))\n sleep(1.7)\n\ndef photo_stack():\n camera('/picam2_focus?focus=' + str(focuslist[0]))\n for i in range(len(focuslist)):\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + \"-F\"+ str(i+1))\n \n focus_thread = threading.Thread(target=stack_focus, args=(i,))\n photo_thread = threading.Thread(target=stack_photo, args=(i,))\n \n focus_thread.start()\n photo_thread.start()\n \n focus_thread.join()\n photo_thread.join()\n\n\n\ndef move_motor():\n rotor_angle = position[0] - position_last[0]\n msg['payload2'].append(rotor_angle)\n #if abs(rotor_angle) > 180:\n # rotor_angle = -360 * rotor_angle / abs(rotor_angle) + rotor_angle\n tt_angle = position_last[1] - position[1]\n if tt_angle > 180:\n tt_angle -= 360\n elif tt_angle < -180:\n tt_angle += 360\n\n motorrun('tt',tt_angle)\n motorrun('rotor',rotor_angle)\n return\n\n # THE FOLLOWING DOES NOT WORK PROPERLY WITH THREADING ?!\n\n #tt_thread = threading.Thread(target=motorrun, args=('tt', tt_angle))\n #rotor_thread = threading.Thread(target=motorrun, args=('rotor', rotor_angle))\n #tt_thread.start()\n #rotor_thread.start()\n #tt_thread.join()\n #rotor_thread.join()\n\n\ncounter2 = 0\n\ndef check_diskspace():\n diskspace_threshold = load_int('diskspace_threshold')\n diskspace = getoutput('df -h / | awk \"{print $5}\"').split('\\n')[1]\n available = int(float(diskspace.replace(' ','').split('G')[2])*1000)\n if available < diskspace_threshold:\n save('status_internal_cam', 'Routine-stopping')\n return\n\ndef focus(i):\n f = focuslist[i]\n camera('/picam2_focus?focus=' + str(f))\n if i < len(focuslist) - 1:\n i += 1\n else:\n i = 0\n return i\n\ndef send_telegram_message(message, telegram_api_token, telegram_client_id):\n telegram_bot_path = '/usr/local/bin/send-telegram'\n run([telegram_bot_path,\"-a\",telegram_api_token,\"-c\",telegram_client_id,\"-m\",message])\n\nif telegram_enable:\n telegram_message = \"[START] \" + hostname + \" starting \" + projectname + \"(\" + str(photocount) + \" photos) ETA: \"\n try:\n send_telegram_message(telegram_message, telegram_api_token, telegram_client_id)\n except Exception as e:\n print(e)\nfor position in coordinates:\n counter += 1\n filepath = basepath + 'tmp/' + projectname + '_' + str(counter) + \".jpg\"\n if load_str('status_internal_cam') == \"Routine-stopping\":\n break\n if counter < 6:\n ETA = ''\n\n save('status_internal_cam', 'Routine-Photo ' + str(counter) + '/' + str(photocount) + ETA)\n if counter > 6:\n check_diskspace()\n\n move_motor()\n sleep(load_float(\"cam_delay_before\"))\n \n if stacksize ==1:\n returning = [counter2]\n photo(returning)\n counter2 = returning[0]\n\n else:\n photo_stack()\n\n sleep(load_float(\"cam_delay_after\"))\n ETA = '-ETA:' + str(int((photocount / counter - 1) * (time() - starttime))) + '/' + str(\n int(photocount / counter * (time() - starttime))) + 's'\n position_last = position\n\nzip.close()\ntry:\n send_telegram_message(\"[STOP] \" + hostname + \" stop \" + projectname, telegram_api_token, telegram_client_id)\nexcept Exception as e:\n print(e)\ncamera('/picam2_switch_mode?mode=0')\n\nsave('status_internal_cam', 'Routine-done')\n\nmotorrun('rotor', -position_last[0] )\nmotorrun('tt', position_last[1])\n\nsave('status_internal_cam', '--READY--')\n\nsystem('mv ' + zippath + \" \" + basepath + \"scans/\" + projectcode + \".zip\")\n\nreturn msg\n", "outputs": 1, "x": 300, "y": 1040, "wires": [ [ - "1daf9e3a5bd5ab48" + "1daf9e3a5bd5ab48", + "795c85ad4f109567" ] ] }, @@ -2301,7 +2309,7 @@ "order": 4, "width": 7, "height": 1, - "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", + "format": "\n \n \n
\n
\n
\n {{sliderName}}\n
\n
\n \n \n \n
\n
\n
\n \n \n
\n
\n\n\n
", "storeOutMessages": true, "fwdInMessages": true, "resendOnRefresh": true, @@ -2637,20 +2645,19 @@ ] }, { - "id": "e78235c36be29dbf", + "id": "795c85ad4f109567", "type": "debug", "z": "481edaf6db5a7a54", - "name": "debug 9", + "name": "debug 5", "active": true, "tosidebar": true, "console": false, "tostatus": false, - "complete": "true", - "targetType": "full", + "complete": "false", "statusVal": "", "statusType": "auto", - "x": 500, - "y": 960, + "x": 620, + "y": 1000, "wires": [] }, { @@ -2665,8 +2672,7 @@ "wires": [ [ "f3662f8c7d3d7a2d", - "01e4783e148c6698", - "332d0b0957b80b33" + "01e4783e148c6698" ] ] }, @@ -2676,11 +2682,11 @@ "z": "80a3942785a26c29", "name": "filelist", "links": [ + "50eeb3e362f9027f", "960912e90ba5b5bc", "a4f09e25.02569", "ed35109311335099", - "fb13752beddee9f2", - "50eeb3e362f9027f" + "fb13752beddee9f2" ], "x": 355, "y": 220, @@ -3016,8 +3022,7 @@ "wires": [ [ "ea54fcc2.cfcc2", - "b42e061fb1f1f3d7", - "df2a071988c4c723" + "b42e061fb1f1f3d7" ], [ "6434e713f088012b" @@ -3151,7 +3156,7 @@ "type": "python3-function", "z": "80a3942785a26c29", "name": "del", - "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if os.path.isdir(dir + i):\n shutil.rmtree(dir + i)\n else:\n os.remove(dir + i)\n\nreturn msg", + "func": "import os\nimport shutil\n\ndir=\"/home/pi/OpenScan/scans/\"\n\nif msg['payload']==\"No\":\n return\n\nfor i in os.listdir(dir):\n if not os.path.isdir(dir + i):\n os.remove(dir + i)\n\n\ndir=\"/home/pi/OpenScan/scans/preview/\"\n\nfor i in os.listdir(dir):\n os.remove(dir + i)\n\nreturn msg\n", "outputs": 1, "x": 690, "y": 340, @@ -3631,35 +3636,6 @@ ] ] }, - { - "id": "50020809fbd23673", - "type": "inject", - "z": "80a3942785a26c29", - "name": "", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "", - "payloadType": "date", - "x": 320, - "y": 260, - "wires": [ - [ - "ea54fcc2.cfcc2" - ] - ] - }, { "id": "01e4783e148c6698", "type": "ui_table", @@ -3744,40 +3720,6 @@ ] ] }, - { - "id": "df2a071988c4c723", - "type": "debug", - "z": "80a3942785a26c29", - "name": "debug 7", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 460, - "y": 80, - "wires": [] - }, - { - "id": "332d0b0957b80b33", - "type": "debug", - "z": "80a3942785a26c29", - "name": "debug 8", - "active": true, - "tosidebar": true, - "console": false, - "tostatus": false, - "complete": "true", - "targetType": "full", - "statusVal": "", - "statusType": "auto", - "x": 675, - "y": 59, - "wires": [] - }, { "id": "cb3437ec113e1b6f", "type": "ui_switch", @@ -4082,7 +4024,7 @@ "animate": false, "className": "", "x": 400, - "y": 460, + "y": 480, "wires": [ [ "f06a7bcad524e9f9" @@ -4097,7 +4039,7 @@ "func": "from OpenScan import save\n\nif msg['payload'] != 'OK':\n msg['payload'] = False\n return None,msg\n \nsave('advanced_settings', True)\n\nreturn msg", "outputs": 2, "x": 820, - "y": 460, + "y": 480, "wires": [ [ "8750ad979e9ea246" @@ -4238,8 +4180,8 @@ "payloadType": "str", "topic": "topic", "topicType": "msg", - "x": 580, - "y": 200, + "x": 740, + "y": 260, "wires": [ [ "5fff689f9f8bc1ca" @@ -4691,7 +4633,7 @@ "name": "Motor", "info": "", "x": 90, - "y": 1620, + "y": 1740, "wires": [] }, { @@ -4701,7 +4643,7 @@ "name": "Camera", "info": "", "x": 90, - "y": 2260, + "y": 2500, "wires": [] }, { @@ -4711,7 +4653,7 @@ "name": "Pinout", "info": "", "x": 90, - "y": 2720, + "y": 2960, "wires": [] }, { @@ -4722,7 +4664,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 12, + "order": 16, "width": 3, "height": 1, "passthru": false, @@ -4734,7 +4676,7 @@ "step": "0.005", "className": "", "x": 450, - "y": 1860, + "y": 2100, "wires": [ [ "11fd3363416433f9" @@ -4749,7 +4691,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 25, + "order": 30, "width": 3, "height": 1, "passthru": false, @@ -4761,7 +4703,7 @@ "step": "0.005", "className": "", "x": 420, - "y": 2100, + "y": 2340, "wires": [ [ "e50492d1e18f43c6" @@ -4776,7 +4718,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 14, + "order": 18, "width": 3, "height": 1, "passthru": false, @@ -4788,7 +4730,7 @@ "step": "0.1", "className": "", "x": 420, - "y": 1900, + "y": 2140, "wires": [ [ "e8b24efb0f30288e" @@ -4803,7 +4745,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 16, + "order": 20, "width": 3, "height": 1, "passthru": false, @@ -4815,7 +4757,7 @@ "step": "100", "className": "", "x": 440, - "y": 1940, + "y": 2180, "wires": [ [ "29f576be9e292232" @@ -4830,7 +4772,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 10, + "order": 14, "width": 3, "height": 1, "passthru": false, @@ -4841,7 +4783,7 @@ "className": "", "topicType": "msg", "x": 460, - "y": 1820, + "y": 2060, "wires": [ [ "78e256083f59f66f" @@ -4853,7 +4795,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 15, + "order": 19, "width": 3, "height": 1, "name": "rotor Accramp", @@ -4862,7 +4804,7 @@ "layout": "row-left", "className": "", "x": 780, - "y": 1900, + "y": 2140, "wires": [] }, { @@ -4870,7 +4812,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 9, + "order": 13, "width": 3, "height": 1, "name": "rotor_Steps per Rotation", @@ -4879,7 +4821,7 @@ "layout": "row-spread", "className": "", "x": 810, - "y": 1940, + "y": 2180, "wires": [] }, { @@ -4887,7 +4829,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 13, + "order": 17, "width": 3, "height": 1, "name": "rotor Acc", @@ -4896,7 +4838,7 @@ "layout": "row-left", "className": "", "x": 760, - "y": 1860, + "y": 2100, "wires": [] }, { @@ -4904,7 +4846,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 11, + "order": 15, "width": 3, "height": 1, "name": "rotor_delay", @@ -4913,7 +4855,7 @@ "layout": "row-left", "className": "", "x": 770, - "y": 1820, + "y": 2060, "wires": [] }, { @@ -4921,7 +4863,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 21, + "order": 26, "width": 6, "height": 1, "name": "tt", @@ -4930,7 +4872,7 @@ "layout": "row-center", "className": "", "x": 90, - "y": 2060, + "y": 2300, "wires": [] }, { @@ -4941,7 +4883,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 27, + "order": 32, "width": 3, "height": 1, "passthru": false, @@ -4953,7 +4895,7 @@ "step": "0.1", "className": "", "x": 410, - "y": 2140, + "y": 2380, "wires": [ [ "af88b9da72917d62" @@ -4968,7 +4910,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 29, + "order": 34, "width": 3, "height": 1, "passthru": false, @@ -4980,7 +4922,7 @@ "step": "1", "className": "", "x": 430, - "y": 2180, + "y": 2420, "wires": [ [ "b1b4678827d3a6dd" @@ -4995,7 +4937,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 23, + "order": 28, "width": 3, "height": 1, "passthru": false, @@ -5006,7 +4948,7 @@ "className": "", "topicType": "msg", "x": 450, - "y": 2060, + "y": 2300, "wires": [ [ "eef89545ec0f6aa8" @@ -5018,7 +4960,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 28, + "order": 33, "width": 3, "height": 1, "name": "ttAccramp", @@ -5027,7 +4969,7 @@ "layout": "row-left", "className": "", "x": 760, - "y": 2180, + "y": 2420, "wires": [] }, { @@ -5035,7 +4977,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 22, + "order": 27, "width": 3, "height": 1, "name": "tt_steps per Rotation", @@ -5044,7 +4986,7 @@ "layout": "row-spread", "className": "", "x": 800, - "y": 2060, + "y": 2300, "wires": [] }, { @@ -5052,7 +4994,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 26, + "order": 31, "width": 3, "height": 1, "name": "tt Acc", @@ -5061,7 +5003,7 @@ "layout": "row-left", "className": "", "x": 750, - "y": 2140, + "y": 2380, "wires": [] }, { @@ -5069,7 +5011,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 24, + "order": 29, "width": 3, "height": 1, "name": "tt_delay", @@ -5078,7 +5020,7 @@ "layout": "row-left", "className": "", "x": 760, - "y": 2100, + "y": 2340, "wires": [] }, { @@ -5089,7 +5031,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 18, + "order": 22, "width": 3, "height": 1, "passthru": false, @@ -5101,7 +5043,7 @@ "step": "1", "className": "", "x": 430, - "y": 1980, + "y": 2220, "wires": [ [ "c4b5a38c5c1df3d2" @@ -5113,7 +5055,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 17, + "order": 21, "width": 3, "height": 1, "name": "rotor_angle", @@ -5122,7 +5064,7 @@ "layout": "row-spread", "className": "", "x": 770, - "y": 1980, + "y": 2220, "wires": [] }, { @@ -5133,7 +5075,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 31, + "order": 36, "width": 3, "height": 1, "passthru": false, @@ -5145,7 +5087,7 @@ "step": "1", "className": "", "x": 420, - "y": 2220, + "y": 2460, "wires": [ [ "0f3367983bb8e159" @@ -5157,7 +5099,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 30, + "order": 35, "width": 3, "height": 1, "name": "tt_angle", @@ -5166,7 +5108,7 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2220, + "y": 2460, "wires": [] }, { @@ -5183,7 +5125,7 @@ "layout": "row-center", "className": "", "x": 90, - "y": 1700, + "y": 1820, "wires": [] }, { @@ -5194,7 +5136,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 33, + "order": 38, "width": 3, "height": 1, "passthru": false, @@ -5206,7 +5148,7 @@ "step": "1", "className": "", "x": 410, - "y": 2260, + "y": 2500, "wires": [ [ "c9d2e31514def4fc" @@ -5221,7 +5163,7 @@ "label": "", "tooltip": "", "group": "7a3279eea439bcdd", - "order": 20, + "order": 24, "width": 3, "height": 1, "passthru": false, @@ -5233,7 +5175,7 @@ "step": "1", "className": "", "x": 420, - "y": 2020, + "y": 2260, "wires": [ [ "523717b0f218a5fd" @@ -5245,7 +5187,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 32, + "order": 37, "width": 3, "height": 1, "name": "tt_dir", @@ -5254,7 +5196,7 @@ "layout": "row-spread", "className": "", "x": 750, - "y": 2260, + "y": 2500, "wires": [] }, { @@ -5262,7 +5204,7 @@ "type": "ui_text", "z": "e43a27722b508115", "group": "7a3279eea439bcdd", - "order": 19, + "order": 23, "width": 3, "height": 1, "name": "rotor_dir", @@ -5271,7 +5213,7 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2020, + "y": 2260, "wires": [] }, { @@ -5300,7 +5242,7 @@ "46b91bef44714366" ], "x": 955, - "y": 460, + "y": 480, "wires": [] }, { @@ -5323,7 +5265,7 @@ "step": "0.02", "className": "", "x": 430, - "y": 2360, + "y": 2600, "wires": [ [ "5c752757090c49d2" @@ -5350,7 +5292,7 @@ "step": "0.1", "className": "", "x": 400, - "y": 2400, + "y": 2640, "wires": [ [ "a1769f0277834f6d" @@ -5377,7 +5319,7 @@ "step": "0.1", "className": "", "x": 420, - "y": 2520, + "y": 2760, "wires": [ [ "1a8b0ba21b4f3005", @@ -5405,7 +5347,7 @@ "step": "0.1", "className": "", "x": 420, - "y": 2560, + "y": 2800, "wires": [ [ "dc8fc962ff7d594b", @@ -5433,7 +5375,7 @@ "step": "1", "className": "", "x": 410, - "y": 2600, + "y": 2840, "wires": [ [ "00e7836ccb3c4d0c" @@ -5454,7 +5396,7 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2360, + "y": 2600, "wires": [] }, { @@ -5471,7 +5413,7 @@ "layout": "row-spread", "className": "", "x": 740, - "y": 2400, + "y": 2640, "wires": [] }, { @@ -5488,7 +5430,7 @@ "layout": "row-spread", "className": "", "x": 750, - "y": 2520, + "y": 2760, "wires": [] }, { @@ -5505,7 +5447,7 @@ "layout": "row-spread", "className": "", "x": 750, - "y": 2560, + "y": 2800, "wires": [] }, { @@ -5522,7 +5464,7 @@ "layout": "row-spread", "className": "", "x": 740, - "y": 2600, + "y": 2840, "wires": [] }, { @@ -5544,7 +5486,7 @@ "className": "", "topicType": "msg", "x": 390, - "y": 2760, + "y": 3000, "wires": [ [ "885bc559fafec5f2" @@ -5565,7 +5507,7 @@ "layout": "row-spread", "className": "", "x": 730, - "y": 2760, + "y": 3000, "wires": [] }, { @@ -5587,7 +5529,7 @@ "className": "", "topicType": "msg", "x": 390, - "y": 2800, + "y": 3040, "wires": [ [ "f70321c96bf81360" @@ -5608,7 +5550,7 @@ "layout": "row-spread", "className": "", "x": 730, - "y": 2800, + "y": 3040, "wires": [] }, { @@ -5630,7 +5572,7 @@ "className": "", "topicType": "msg", "x": 390, - "y": 2840, + "y": 3080, "wires": [ [ "95e1603bbd06a69d" @@ -5651,7 +5593,7 @@ "layout": "row-spread", "className": "", "x": 730, - "y": 2840, + "y": 3080, "wires": [] }, { @@ -5673,7 +5615,7 @@ "className": "", "topicType": "msg", "x": 400, - "y": 2880, + "y": 3120, "wires": [ [ "a8f92ea6bf394640" @@ -5694,7 +5636,7 @@ "layout": "row-spread", "className": "", "x": 740, - "y": 2880, + "y": 3120, "wires": [] }, { @@ -5716,7 +5658,7 @@ "className": "", "topicType": "msg", "x": 400, - "y": 2920, + "y": 3160, "wires": [ [ "06397bb46b3bb541" @@ -5737,7 +5679,7 @@ "layout": "row-spread", "className": "", "x": 740, - "y": 2920, + "y": 3160, "wires": [] }, { @@ -5759,7 +5701,7 @@ "className": "", "topicType": "msg", "x": 400, - "y": 2960, + "y": 3200, "wires": [ [ "687dcdc1ede11700" @@ -5780,7 +5722,7 @@ "layout": "row-spread", "className": "", "x": 740, - "y": 2960, + "y": 3200, "wires": [] }, { @@ -5802,7 +5744,7 @@ "className": "", "topicType": "msg", "x": 390, - "y": 3000, + "y": 3240, "wires": [ [ "e220740c0d38ccb0" @@ -5823,7 +5765,7 @@ "layout": "row-spread", "className": "", "x": 730, - "y": 3000, + "y": 3240, "wires": [] }, { @@ -5845,7 +5787,7 @@ "className": "", "topicType": "msg", "x": 390, - "y": 3040, + "y": 3280, "wires": [ [ "79d7e5a705ab813a" @@ -5866,7 +5808,7 @@ "layout": "row-spread", "className": "", "x": 730, - "y": 3040, + "y": 3280, "wires": [] }, { @@ -5888,7 +5830,7 @@ "className": "", "topicType": "msg", "x": 400, - "y": 3080, + "y": 3320, "wires": [ [ "12d20f2274bcc511" @@ -5909,7 +5851,7 @@ "layout": "row-spread", "className": "", "x": 740, - "y": 3080, + "y": 3320, "wires": [] }, { @@ -5931,7 +5873,7 @@ "className": "", "topicType": "msg", "x": 400, - "y": 3120, + "y": 3360, "wires": [ [ "a4a89668ce4c9f05" @@ -5952,7 +5894,7 @@ "layout": "row-spread", "className": "", "x": 740, - "y": 3120, + "y": 3360, "wires": [] }, { @@ -5971,7 +5913,7 @@ "topic": "", "name": "confirm", "x": 680, - "y": 460, + "y": 480, "wires": [ [ "29745a36fc157f3f" @@ -5986,7 +5928,7 @@ "func": "from OpenScan import save, load_bool\n\nif msg['payload'] == True and not load_bool('advanced_settings'):\n msg['payload'] = '''

PLEASE READ :)

\n

Modifying the advanced settings can potentially damage your device and/or the connected peripherals.

\n

Please read the given information texts carefully and only change settings, when you are sure about the consequences!

\n'''\n return msg\nelif not msg['payload']: \n save('advanced_settings', False)\n", "outputs": 1, "x": 530, - "y": 460, + "y": 480, "wires": [ [ "5fcef1cb2e9e4788" @@ -6013,7 +5955,7 @@ "step": "90", "className": "", "x": 410, - "y": 2640, + "y": 2880, "wires": [ [ "3019576de193d9d6" @@ -6034,7 +5976,7 @@ "layout": "row-spread", "className": "", "x": 750, - "y": 2640, + "y": 2880, "wires": [] }, { @@ -6049,7 +5991,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1820, + "y": 2060, "wires": [ [ "dfdebe10dbf0e198" @@ -6068,7 +6010,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1820, + "y": 2060, "wires": [ [] ] @@ -6085,7 +6027,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1940, + "y": 2180, "wires": [ [ "9a56c087d941f1da" @@ -6104,7 +6046,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1940, + "y": 2180, "wires": [ [] ] @@ -6121,7 +6063,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1980, + "y": 2220, "wires": [ [ "0dfc86d90258f9bb" @@ -6140,7 +6082,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1980, + "y": 2220, "wires": [ [] ] @@ -6157,7 +6099,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 2020, + "y": 2260, "wires": [ [ "1361134e9847f003" @@ -6176,7 +6118,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 2020, + "y": 2260, "wires": [ [] ] @@ -6193,7 +6135,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1860, + "y": 2100, "wires": [ [ "b03e8b51187e88eb" @@ -6212,7 +6154,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1860, + "y": 2100, "wires": [ [] ] @@ -6229,7 +6171,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1900, + "y": 2140, "wires": [ [ "543e1690693acbeb" @@ -6248,7 +6190,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1900, + "y": 2140, "wires": [ [] ] @@ -6260,12 +6202,12 @@ "name": "loadI", "func": "var file = 'tt_stepsperrotation'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nsteps = parseInt(data);\nif (steps == 3600){\n steps = 3200\n}\n\nmsg.payload = steps\n\nreturn msg", "outputs": 1, - "noerr": 0, + "noerr": 4, "initialize": "", "finalize": "", "libs": [], "x": 290, - "y": 2060, + "y": 2300, "wires": [ [ "c6642c7470d3820c" @@ -6284,7 +6226,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 2180, + "y": 2420, "wires": [ [ "721b9680a3fa460e" @@ -6303,7 +6245,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 2220, + "y": 2460, "wires": [ [ "1610895f430b9aca" @@ -6322,7 +6264,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 2260, + "y": 2500, "wires": [ [ "277037c4716d85bf" @@ -6341,7 +6283,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 2100, + "y": 2340, "wires": [ [ "6aae9d4fddf08cc0" @@ -6360,7 +6302,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 2140, + "y": 2380, "wires": [ [ "10687d331a732790" @@ -6379,7 +6321,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 2060, + "y": 2300, "wires": [ [] ] @@ -6396,7 +6338,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 2180, + "y": 2420, "wires": [ [] ] @@ -6413,7 +6355,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 2220, + "y": 2460, "wires": [ [] ] @@ -6430,7 +6372,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 2260, + "y": 2500, "wires": [ [] ] @@ -6447,7 +6389,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 2100, + "y": 2340, "wires": [ [] ] @@ -6464,7 +6406,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 2140, + "y": 2380, "wires": [ [] ] @@ -6481,7 +6423,7 @@ "finalize": "", "libs": [], "x": 280, - "y": 2360, + "y": 2600, "wires": [ [ "2522f888dc58972f" @@ -6500,7 +6442,7 @@ "finalize": "", "libs": [], "x": 620, - "y": 2360, + "y": 2600, "wires": [ [] ] @@ -6517,7 +6459,7 @@ "finalize": "", "libs": [], "x": 280, - "y": 2400, + "y": 2640, "wires": [ [ "30e8df3d616512d8" @@ -6536,7 +6478,7 @@ "finalize": "", "libs": [], "x": 620, - "y": 2400, + "y": 2640, "wires": [ [] ] @@ -6553,7 +6495,7 @@ "finalize": "", "libs": [], "x": 280, - "y": 2520, + "y": 2760, "wires": [ [ "d855d926df89d65b" @@ -6572,7 +6514,7 @@ "finalize": "", "libs": [], "x": 620, - "y": 2520, + "y": 2760, "wires": [ [] ] @@ -6589,7 +6531,7 @@ "finalize": "", "libs": [], "x": 280, - "y": 2560, + "y": 2800, "wires": [ [ "7617517dc8ba2859" @@ -6608,7 +6550,7 @@ "finalize": "", "libs": [], "x": 620, - "y": 2560, + "y": 2800, "wires": [ [] ] @@ -6625,7 +6567,7 @@ "finalize": "", "libs": [], "x": 280, - "y": 2600, + "y": 2840, "wires": [ [ "cbaa23c34e10fae1" @@ -6644,7 +6586,7 @@ "finalize": "", "libs": [], "x": 620, - "y": 2600, + "y": 2840, "wires": [ [] ] @@ -6661,7 +6603,7 @@ "finalize": "", "libs": [], "x": 280, - "y": 2640, + "y": 2880, "wires": [ [ "f455fb39039617ae" @@ -6680,7 +6622,7 @@ "finalize": "", "libs": [], "x": 620, - "y": 2640, + "y": 2880, "wires": [ [] ] @@ -6697,7 +6639,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 2760, + "y": 3000, "wires": [ [ "e89f61dbe6a6cffe" @@ -6716,7 +6658,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 2760, + "y": 3000, "wires": [ [] ] @@ -6733,7 +6675,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 3080, + "y": 3320, "wires": [ [ "eef25405472acfee" @@ -6752,7 +6694,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 3080, + "y": 3320, "wires": [ [] ] @@ -6769,7 +6711,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 2800, + "y": 3040, "wires": [ [ "70014da0b6ab6698" @@ -6788,7 +6730,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 2800, + "y": 3040, "wires": [ [] ] @@ -6805,7 +6747,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 2840, + "y": 3080, "wires": [ [ "2544963852c6881a" @@ -6824,7 +6766,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 2840, + "y": 3080, "wires": [ [] ] @@ -6841,7 +6783,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 2880, + "y": 3120, "wires": [ [ "a1394401246eb735" @@ -6860,7 +6802,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 2880, + "y": 3120, "wires": [ [] ] @@ -6877,7 +6819,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 2920, + "y": 3160, "wires": [ [ "f15ca4518b5f223e" @@ -6896,7 +6838,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 2920, + "y": 3160, "wires": [ [] ] @@ -6913,7 +6855,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 2960, + "y": 3200, "wires": [ [ "49900bb9047dd965" @@ -6932,7 +6874,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 2960, + "y": 3200, "wires": [ [] ] @@ -6949,7 +6891,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 3000, + "y": 3240, "wires": [ [ "5a90224dc998b417" @@ -6968,7 +6910,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 3040, + "y": 3280, "wires": [ [ "d2364ab09627fe94" @@ -6987,7 +6929,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 3000, + "y": 3240, "wires": [ [] ] @@ -7004,7 +6946,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 3040, + "y": 3280, "wires": [ [] ] @@ -7021,7 +6963,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 3120, + "y": 3360, "wires": [ [ "74e455136b5ca5dd" @@ -7040,7 +6982,7 @@ "finalize": "", "libs": [], "x": 590, - "y": 3120, + "y": 3360, "wires": [ [] ] @@ -7050,7 +6992,7 @@ "type": "function", "z": "e43a27722b508115", "name": "loadB", - "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "func": "var file = 'ssh'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", @@ -7069,7 +7011,7 @@ "type": "function", "z": "e43a27722b508115", "name": "loadB", - "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "func": "var file = 'smb'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", "outputs": 1, "noerr": 0, "initialize": "", @@ -7095,7 +7037,7 @@ "finalize": "", "libs": [], "x": 270, - "y": 460, + "y": 480, "wires": [ [ "f6d6cc35679ede63" @@ -7169,7 +7111,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1700, + "y": 1820, "wires": [ [ "6ebd15c61a5ca891" @@ -7190,7 +7132,7 @@ "layout": "row-left", "className": "", "x": 780, - "y": 1700, + "y": 1820, "wires": [] }, { @@ -7205,7 +7147,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1700, + "y": 1820, "wires": [ [] ] @@ -7230,7 +7172,7 @@ "step": "5", "className": "", "x": 440, - "y": 1700, + "y": 1820, "wires": [ [ "acd10a4c99ee8063" @@ -7257,7 +7199,7 @@ "step": "5", "className": "", "x": 440, - "y": 1740, + "y": 1860, "wires": [ [ "031d7697768d0e77" @@ -7284,7 +7226,7 @@ "step": "5", "className": "", "x": 440, - "y": 1780, + "y": 1900, "wires": [ [ "be1954dd71d2c94c" @@ -7303,7 +7245,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1740, + "y": 1860, "wires": [ [ "3ad0f0f206e4a873" @@ -7322,7 +7264,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1740, + "y": 1860, "wires": [ [] ] @@ -7339,7 +7281,7 @@ "finalize": "", "libs": [], "x": 290, - "y": 1780, + "y": 1900, "wires": [ [ "3b6d759ed5be647f" @@ -7358,7 +7300,7 @@ "finalize": "", "libs": [], "x": 630, - "y": 1780, + "y": 1900, "wires": [ [] ] @@ -7377,7 +7319,7 @@ "layout": "row-left", "className": "", "x": 780, - "y": 1740, + "y": 1860, "wires": [] }, { @@ -7394,7 +7336,7 @@ "layout": "row-left", "className": "", "x": 780, - "y": 1780, + "y": 1900, "wires": [] }, { @@ -7403,8 +7345,8 @@ "z": "e43a27722b508115", "name": "enable projectname", "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" + "50eeb3e362f9027f", + "960912e90ba5b5bc" ], "x": 135, "y": 360, @@ -7412,7 +7354,8 @@ [ "22ef66b0e2058be2", "9ce01c8ba97932c1", - "81356177176eebcf" + "81356177176eebcf", + "d54b85891248ba88" ] ] }, @@ -7446,7 +7389,7 @@ "50eeb3e362f9027f" ], "x": 185, - "y": 1700, + "y": 1820, "wires": [ [ "0f0871baf322b6d0", @@ -7463,7 +7406,9 @@ "6b2eb1cb95e573f9", "ed4d587cb4feb064", "5b02160c33605ae7", - "304c135ec09801e3" + "304c135ec09801e3", + "f036424d79645761", + "b7db72b7f0599ebd" ] ] }, @@ -7473,11 +7418,11 @@ "z": "e43a27722b508115", "name": "enable projectname", "links": [ - "960912e90ba5b5bc", - "50eeb3e362f9027f" + "50eeb3e362f9027f", + "960912e90ba5b5bc" ], "x": 155, - "y": 2300, + "y": 2540, "wires": [ [ "43fe948b3e7234e2", @@ -7500,7 +7445,7 @@ "50eeb3e362f9027f" ], "x": 135, - "y": 2760, + "y": 3000, "wires": [ [ "77bb7dc529d63a7e", @@ -7636,7 +7581,7 @@ "bgcolor": "transparent", "className": "", "icon": "fa-question-circle", - "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", + "payload": "

Update&Log

Status

See whether new updates are available. It is highly recommended to use the latest firmware version. See OpenScan2 on Github.com for details and the source code.

Updatetype

- stable: latest well-tested and mostly bug-free version for the OpenScanMini or Classic and various cameras

- beta: stable version + some experimental and new features, which might bring joy and some new bugs as well

- mini: very simplified firmware for the OpenScanMini + Arducam IMX519

Auto-Check update availability

Perform an automated update-check after each start of the device. If the device is connected to the internet, it will get the latest files from OpenScan2 on Github.com

This option is activated by default.

Check Updates

Alternatively, you can check for updates manually at any time by pressing this button.

Download Error Log

In case you encounter any errors with your device, please download the error log text and send a copy to info@openscan.eu or create an issue on Github.com

", "payloadType": "str", "topic": "topic", "topicType": "msg", @@ -7656,7 +7601,7 @@ "func": "from OpenScan import camera\n\ncamera(\"/picam2_contrast?contrast=\" + str(msg['payload']))", "outputs": 1, "x": 660, - "y": 2480, + "y": 2720, "wires": [ [] ] @@ -7669,7 +7614,7 @@ "func": "from OpenScan import camera\n\ncamera(\"/picam2_saturation?saturation=\" + str(msg['payload']))", "outputs": 1, "x": 660, - "y": 2440, + "y": 2680, "wires": [ [] ] @@ -7694,7 +7639,7 @@ "step": "0.02", "className": "", "x": 440, - "y": 2320, + "y": 2560, "wires": [ [ "e612073aded01a8f" @@ -7715,7 +7660,7 @@ "layout": "row-spread", "className": "", "x": 760, - "y": 2320, + "y": 2560, "wires": [] }, { @@ -7730,7 +7675,7 @@ "finalize": "", "libs": [], "x": 280, - "y": 2320, + "y": 2560, "wires": [ [ "81bd4381cd029958" @@ -7749,7 +7694,7 @@ "finalize": "", "libs": [], "x": 620, - "y": 2320, + "y": 2560, "wires": [ [] ] @@ -8098,84 +8043,585 @@ "wires": [] }, { - "id": "4c7fa5b5b27b83a5", - "type": "python3-function", - "z": "a5557543ccff5889", - "name": "create beta new", - "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'betaArdu'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", - "outputs": 1, - "x": 260, - "y": 140, + "id": "6b7245c3dcb694c8", + "type": "ui_slider", + "z": "e43a27722b508115", + "name": "endstop_angle", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 12, + "width": 3, + "height": 1, + "passthru": false, + "outs": "end", + "topic": "", + "topicType": "str", + "min": "-90", + "max": "90", + "step": "1", + "className": "", + "x": 440, + "y": 2020, "wires": [ [ - "e23c514008cad1a1" + "85ad07b8f973bbe2" ] ] }, { - "id": "80175eb8dc6ad009", - "type": "inject", - "z": "a5557543ccff5889", - "name": "", - "props": [ - { - "p": "payload" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "payload": "", - "payloadType": "date", - "x": 100, - "y": 140, - "wires": [ - [ - "4c7fa5b5b27b83a5" - ] - ] + "id": "69516440e3997111", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 11, + "width": 3, + "height": 1, + "name": "endstop_angle", + "label": "Endstop angle", + "format": "", + "layout": "row-left", + "className": "", + "x": 780, + "y": 2020, + "wires": [] }, { - "id": "d7362e6e0ec7bdaa", - "type": "inject", - "z": "a5557543ccff5889", - "name": "", - "props": [ - { - "p": "overwrite", - "v": "true", - "vt": "bool" - }, - { - "p": "topic", - "vt": "str" - } - ], - "repeat": "", - "crontab": "", - "once": false, - "onceDelay": 0.1, - "topic": "", - "x": 90, - "y": 220, + "id": "85ad07b8f973bbe2", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 2020, "wires": [ - [ - "4ce127c61c3c5966", - "beacc3dc5398fa79" - ] + [] ] }, { - "id": "4ce127c61c3c5966", - "type": "python3-function", - "z": "a5557543ccff5889", - "name": "prepare image creation", + "id": "f036424d79645761", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'rotor_endstop_angle'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = parseInt(data);\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 2020, + "wires": [ + [ + "6b7245c3dcb694c8" + ] + ] + }, + { + "id": "253feafa5a2f8b1d", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "rotor_enable_endstop", + "label": "", + "tooltip": "", + "group": "7a3279eea439bcdd", + "order": 10, + "width": 3, + "height": 1, + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 460, + "y": 1940, + "wires": [ + [ + "1916dc3fd04f0664", + "6cb92b9b9f0d6954" + ] + ] + }, + { + "id": "b7db72b7f0599ebd", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data = fs.readFileSync(filepath+file, 'utf8');\nif(data === '1' || data === 'True' || data === 'true'){\n data = true;\n}\nelse{\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 290, + "y": 1940, + "wires": [ + [ + "253feafa5a2f8b1d" + ] + ] + }, + { + "id": "1916dc3fd04f0664", + "type": "function", + "z": "e43a27722b508115", + "name": "write", + "func": "var file = 'rotor_enable_endstop'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n });", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 630, + "y": 1940, + "wires": [ + [] + ] + }, + { + "id": "de409e57a0c4bf41", + "type": "ui_text", + "z": "e43a27722b508115", + "group": "7a3279eea439bcdd", + "order": 9, + "width": 3, + "height": 1, + "name": "rotor_enable_endstop", + "label": "Enable Endstop", + "format": "", + "layout": "row-left", + "className": "", + "x": 800, + "y": 1940, + "wires": [] + }, + { + "id": "6cb92b9b9f0d6954", + "type": "function", + "z": "e43a27722b508115", + "name": "msg", + "func": "msg.enabled = msg.payload\nreturn msg;", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 410, + "y": 1980, + "wires": [ + [ + "69516440e3997111", + "f036424d79645761" + ] + ] + }, + { + "id": "d54b85891248ba88", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'group_stack_photos'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 440, + "wires": [ + [ + "eefed04c25e3e4d6" + ] + ] + }, + { + "id": "eefed04c25e3e4d6", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "", + "label": "Group Stack Photos", + "tooltip": "Group photos that are part of the same focus photoset", + "group": "d324f0b852c2df0a", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 440, + "y": 440, + "wires": [ + [ + "2aaf7c7f0f0c146f" + ] + ] + }, + { + "id": "2aaf7c7f0f0c146f", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "group_stack_photos", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('group_stack_photos'):\n save('group_stack_photos', state)\n", + "outputs": 1, + "x": 660, + "y": 440, + "wires": [ + [] + ] + }, + { + "id": "84a1d063a2a2b018", + "type": "comment", + "z": "e43a27722b508115", + "name": "Messaging", + "info": "", + "x": 100, + "y": 3500, + "wires": [] + }, + { + "id": "a12ead9ccf239c19", + "type": "function", + "z": "e43a27722b508115", + "name": "loadB", + "func": "var file = 'telegram_enable'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nvar data;\ndata = fs.readFileSync(filepath + file, 'utf8');\nif (data === '1' || data === 'True' || data === 'true') {\n data = true;\n}\nelse {\n data = false;\n}\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3560, + "wires": [ + [ + "d0a1a4947a1137ca" + ] + ] + }, + { + "id": "9a4c3cbe89994626", + "type": "python3-function", + "z": "e43a27722b508115", + "name": "telegram_enable", + "func": "from OpenScan import load_bool, save\n\nstate = msg['payload']\n\nif state != load_bool('telegram_enable'):\n save('telegram_enable', state)\n", + "outputs": 1, + "x": 520, + "y": 3560, + "wires": [ + [] + ] + }, + { + "id": "d0a1a4947a1137ca", + "type": "ui_switch", + "z": "e43a27722b508115", + "name": "telegram_enable", + "label": "Enable Telegram", + "tooltip": "Enable telegram bot", + "group": "220493325bb79987", + "order": 1, + "width": "6", + "height": "1", + "passthru": true, + "decouple": "false", + "topic": "topic", + "topicType": "msg", + "style": "", + "onvalue": "true", + "onvalueType": "bool", + "onicon": "", + "oncolor": "", + "offvalue": "false", + "offvalueType": "bool", + "officon": "", + "offcolor": "", + "animate": false, + "className": "", + "x": 340, + "y": 3560, + "wires": [ + [ + "9a4c3cbe89994626" + ] + ] + }, + { + "id": "28eeaa3a8eb77679", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "label": "Telegram Api Token", + "tooltip": "telegram api token", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "password", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3600, + "wires": [ + [ + "1c08a329bd2a669c" + ] + ] + }, + { + "id": "bf8e971a52cddab1", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3600, + "wires": [ + [ + "28eeaa3a8eb77679" + ] + ] + }, + { + "id": "1c08a329bd2a669c", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_api_token", + "func": "var file = 'telegram_api_token'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3600, + "wires": [ + [] + ] + }, + { + "id": "a26c0482377667c9", + "type": "ui_text_input", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "label": "Telegram Client Id", + "tooltip": "The Id of the user or channel to send the message to", + "group": "220493325bb79987", + "order": 5, + "width": 6, + "height": 1, + "passthru": false, + "mode": "text", + "delay": "0", + "topic": "topic", + "sendOnBlur": true, + "className": "", + "topicType": "msg", + "x": 350, + "y": 3640, + "wires": [ + [ + "b5aba11033c5f952" + ] + ] + }, + { + "id": "058743d0e5afb87b", + "type": "function", + "z": "e43a27722b508115", + "name": "loadI", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\nconst data = fs.readFileSync(filepath+file, 'utf8');\nmsg.payload = data;\nreturn msg", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 190, + "y": 3640, + "wires": [ + [ + "a26c0482377667c9" + ] + ] + }, + { + "id": "b5aba11033c5f952", + "type": "function", + "z": "e43a27722b508115", + "name": "telegram_client_id", + "func": "var file = 'telegram_client_id'\nlet fs = global.get('fs');\nvar filepath = '/home/pi/OpenScan/settings/';\n\nconst content = String(msg.payload)\nfs.writeFile(filepath + file, content, err => {\n if (err) {\n return\n }\n});", + "outputs": 1, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 550, + "y": 3640, + "wires": [ + [] + ] + }, +{ + "id": "c59e7b205d80fe0a", + "type": "ui_button", + "z": "e43a27722b508115", + "name": "Messaging", + "group": "220493325bb79987", + "order": 1, + "width": 0, + "height": 0, + "passthru": false, + "label": "", + "tooltip": "", + "color": "", + "bgcolor": "transparent", + "className": "", + "icon": "fa-question-circle", + "payload": "

Messaging

Telegram Messaging

This adds the capability to send OpenScan status messages to Telegram. Please refer to the appropiate documentation in order to configure it

", + "payloadType": "str", + "topic": "topic", + "topicType": "msg", + "x": 770, + "y": 300, + "wires": [ + [ + "5fff689f9f8bc1ca" + ] + ] + }, +{ + "id": "2afb6a45c73fa244", + "type": "link in", + "z": "e43a27722b508115", + "name": "link in 2", + "links": [ + "50eeb3e362f9027f", + "960912e90ba5b5bc" + ], + "x": 65, + "y": 3600, + "wires": [ + [ + "a12ead9ccf239c19", + "bf8e971a52cddab1", + "058743d0e5afb87b" + ] + ] + }, + { + "id": "4c7fa5b5b27b83a5", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "create beta new", + "func": "import json\nimport requests\nimport shutil\n\n#scope = 'main'\nscope = 'stable'\n\nupdatepath = '/home/pi/OpenScan/tmp/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\n\n## load update.json\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'download update.json failed'\n return msg\n\nmsg = {}\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg2 = msg.copy()\nif scope in msg:\n del msg[scope]\n\nmsg[scope]={}\nmsg[scope]['1'] = {}\nmsg[scope]['1']['src'] = scope + '/fla.py'\nmsg[scope]['1']['dst'] = '/home/pi/OpenScan/files/fla.py'\n\nmsg[scope]['2'] = {}\nmsg[scope]['2']['src'] = scope + '/OpenScan.py'\nmsg[scope]['2']['dst'] = '/usr/lib/python3/dist-packages/OpenScan.py'\n\nmsg[scope]['3'] = {}\nmsg[scope]['3']['src'] = scope + '/config.txt'\nmsg[scope]['3']['dst'] = '/boot/config.txt'\n\nmsg[scope]['4'] = {}\nmsg[scope]['4']['src'] = scope + '/flows.json'\nmsg[scope]['4']['dst'] = '/home/pi/OpenScan/settings/.node-red/flows.json'\n\nmsg[scope]['5'] = {}\nmsg[scope]['5']['src'] = scope + '/settings.js'\nmsg[scope]['5']['dst'] = '/root/.node-red/settings.js'\n\n#msg[scope]['6'] = {}\n#msg[scope]['6']['src'] = 'files/logo.jpg'\n#msg[scope]['6']['dst'] = '/home/pi/OpenScan/files/logo.jpg'\n\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n filesize = os.path.getsize(filepath)\n msg[scope][i]['filesize'] = filesize\n\nif os.path.isdir('/home/pi/OpenScan/tmp/update/'):\n os.system('rm -r /home/pi/OpenScan/tmp/update') \nos.makedirs('/home/pi/OpenScan/tmp/update/')\n\nwith open('/home/pi/OpenScan/tmp/update/update.json', 'w+') as f:\n json.dump(msg, f, indent=4)\n\nfor i in msg[scope]:\n if not os.path.isdir(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])):\n os.makedirs(os.path.dirname('/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src']))\n shutil.copy(msg[scope][i]['dst'], '/home/pi/OpenScan/tmp/update/' + msg[scope][i]['src'])\n\nmsg['payload'] = 'created with scope: ' + scope\n\nreturn msg", + "outputs": 1, + "x": 260, + "y": 140, + "wires": [ + [ + "e23c514008cad1a1" + ] + ] + }, + { + "id": "80175eb8dc6ad009", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "payload" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "", + "payloadType": "date", + "x": 100, + "y": 140, + "wires": [ + [ + "4c7fa5b5b27b83a5" + ] + ] + }, + { + "id": "d7362e6e0ec7bdaa", + "type": "inject", + "z": "a5557543ccff5889", + "name": "", + "props": [ + { + "p": "overwrite", + "v": "true", + "vt": "bool" + }, + { + "p": "topic", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "x": 90, + "y": 220, + "wires": [ + [ + "4ce127c61c3c5966", + "beacc3dc5398fa79" + ] + ] + }, + { + "id": "4ce127c61c3c5966", + "type": "python3-function", + "z": "a5557543ccff5889", + "name": "prepare image creation", "func": "import os\n\n#factory reset, reset wpa, create wpa in boot, rm files\n#should be done before creating a new raspbian image\n\nbasepath = '/home/pi/OpenScan/'\n\n#remove files\n\ndir = basepath + 'scans/'\n\nfor i in ['scans/','tmp/']:\n os.system('rm -r ' + basepath + i)\n os.mkdir(basepath + i)\n\n#delete wifi\ntemp_dir = '/home/pi/OpenScan/tmp/wpa_empty.log'\nwpa_dir = '/etc/wpa_supplicant/wpa_supplicant.conf'\n\nwith open(temp_dir, 'w+') as file:\n file.write('update_config=1\\nctrl_interface=DIR=/var/run/wpa_supplicant\\ncountry=de\\n\\n')\nos.system('mv '+ temp_dir + ' ' + wpa_dir)\nos.system('wpa_cli -i wlan0 reconfigure')\n\n#create new wpa_supplicant.conf\nwith open('/boot/wpa_supplicant.conf','w+') as file:\n file.write('country=de\\nupdate_config=1\\nctrl_interface=/var/run/wpa_supplicant\\n\\nnetwork={\\n scan_ssid=1\\n ssid=\"wlan name\"\\n psk=\"xxxx\"\\n}')\nos.system(\"chmod a+rwx /boot/wpa_supplicant.conf\")\n\n\n#rm tmp dir\n\n\n#stop photos:\nos.system('systemctl stop flask')\nos.system('rm -r ' + basepath + 'tmp')\nos.system('mkdir ' + basepath + 'tmp')\n\nos.system('systemctl stop nodered')\n\n#reset factory\n\n", "outputs": 1, "x": 290, @@ -8219,7 +8665,7 @@ "type": "python3-function", "z": "a5557543ccff5889", "name": "get update", - "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", + "func": "import json\nimport requests\nfrom OpenScan import load_str\n\nif not msg['payload']:\n msg['status'] = '--READY--'\n return msg\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_temp = updatepath + 'update_temp.json'\nupdatepath_old = updatepath + 'update.json'\n\nr = requests.get(url + 'update.json')\n\nif r.status_code != 200:\n msg['status'] = 'no internet connection'\n return msg\n\nwith open(updatepath_temp, 'wb+') as file:\n file.write(r.content)\nwith open(updatepath_temp, 'r') as file:\n msg = json.load(file)\n\nmsg['status'] = 'checking updates'\n\nreturn msg, msg", "outputs": 2, "x": 390, "y": 540, @@ -8254,7 +8700,7 @@ "type": "python3-function", "z": "a5557543ccff5889", "name": "check files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str\n\nscope = load_str('update_type')\nmsg['scope'] = scope\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\nupdatepath_old = updatepath + 'update.json'\n\ncounter = 0\nfor i in msg[scope]:\n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n if os.path.isfile(temp):\n filesize = os.path.getsize(temp)\n msg[scope][i]['filesize2'] = filesize\n if filesize == msg[scope][i]['filesize']:\n msg[scope][i]['update'] = False\n continue\n msg[scope][i]['update'] = True\n\n counter += 1\n\nif counter == 0:\n msg['status'] = 'No new update available'\nelse:\n msg['status'] = 'New update available'\n msg['topic'] = msg['status']\n msg['payload'] = 'Install & reboot now?'\n\nmsg['counter'] = counter\n\nreturn msg\n", "outputs": 1, "x": 550, "y": 560, @@ -8320,7 +8766,7 @@ "options": [ { "label": "stable", - "value": "main", + "value": "stable", "type": "str" }, { @@ -8328,11 +8774,11 @@ "value": "beta", "type": "str" }, - { - "label": "betaArdu", - "value": "betaArdu", + { + "label": "meanwhile", + "value": "meanwhile", "type": "str" - } + } ], "payload": "", "topic": "topic", @@ -8538,7 +8984,7 @@ "type": "python3-function", "z": "a5557543ccff5889", "name": "download files", - "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/OpenScanEu/OpenScan2/main/update/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", + "func": "import json\nimport requests\nimport shutil\nfrom OpenScan import load_str, save\n\n\nscope = msg['scope']\n\nupdatepath = '/home/pi/OpenScan/updates/'\nurl = 'https://raw.githubusercontent.com/stealthizer/OpenScan2/main/update/'\n\nif msg['payload'] != 'YES':\n return\n\ncounter = 0\n\nfor i in msg[scope]:\n if msg[scope][i]['update'] == False:\n continue\n \n filepath = msg[scope][i]['dst']\n temp = updatepath + os.path.basename(filepath)\n \n r = requests.get(url + msg[scope][i]['src'])\n if r.status_code != 200:\n msg['status'] = 'downloading ' + msg[scope][i]['src'] + ' failed'\n return msg\n with open(temp, 'wb+') as file:\n file.write(r.content)\n shutil.copy(temp, msg[scope][i]['dst'])\n \n if msg[scope][i]['dst'] == '/boot/config.txt':\n save('camera','')\n \n counter += 1\n\nmsg['status'] = 'Installed ' + str(counter) + ' of ' + str(msg['counter']) + ' - restarting ...'\n\nif counter == msg['counter']:\n updatepath_temp = updatepath + 'update_temp.json'\n updatepath_old = updatepath + 'update.json'\n shutil.move(updatepath_temp, updatepath_old)\n\nreturn msg\n", "outputs": 1, "x": 880, "y": 560, @@ -8898,7 +9344,7 @@ "type": "python3-function", "z": "a5557543ccff5889", "name": "Changelog", - "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/OpenScan-org/OpenScan-Doc/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", + "func": "import requests\n\ntempfile = '/home/pi/OpenScan/tmp/changelog'\n\nurl = 'https://raw.githubusercontent.com/stealthizer/Openscan2/main/docs/changelog.md'\nr = requests.get(url, allow_redirects=False)\n\nwith open(tempfile,'wb') as file:\n file.write(r.content)\n \nwith open(tempfile, 'r') as file:\n text = file.read()\n \ntext = text.replace('\\n','
').replace('*', '  - ')\nmsg['payload'] = text\n\nreturn msg", "outputs": 1, "x": 430, "y": 640, @@ -8929,4 +9375,4 @@ [] ] } -] \ No newline at end of file +] diff --git a/update/stable/settings.js b/update/stable/settings.js new file mode 100644 index 0000000..357b02b --- /dev/null +++ b/update/stable/settings.js @@ -0,0 +1,512 @@ +/** + * Node-RED Settings created at Thu, 20 Apr 2023 08:41:18 GMT + * + * It can contain any valid JavaScript code that will get run when Node-RED + * is started. + * + * Lines that start with // are commented out. + * Each entry should be separated from the entries above and below by a comma ',' + * + * For more information about individual settings, refer to the documentation: + * https://nodered.org/docs/user-guide/runtime/configuration + * + * The settings are split into the following sections: + * - Flow File and User Directory Settings + * - Security + * - Server Settings + * - Runtime Settings + * - Editor Settings + * - Node Settings + * + **/ +process.env.HOSTNAME = require('os').hostname(); + +module.exports = { + +/******************************************************************************* + * Flow File and User Directory Settings + * - flowFile + * - credentialSecret + * - flowFilePretty + * - userDir + * - nodesDir + ******************************************************************************/ + + /** The file containing the flows. If not set, defaults to flows_.json **/ + flowFile: "flows.json", + + /** By default, credentials are encrypted in storage using a generated key. To + * specify your own secret, set the following property. + * If you want to disable encryption of credentials, set this property to false. + * Note: once you set this property, do not change it - doing so will prevent + * node-red from being able to decrypt your existing credentials and they will be + * lost. + */ + credentialSecret: false, + + /** By default, the flow JSON will be formatted over multiple lines making + * it easier to compare changes when using version control. + * To disable pretty-printing of the JSON set the following property to false. + */ + flowFilePretty: true, + + /** By default, all user data is stored in a directory called `.node-red` under + * the user's home directory. To use a different location, the following + * property can be used + */ + //userDir: '/home/nol/.node-red/', +userDir: '/home/pi/OpenScan/settings/.node-red/', + + /** Node-RED scans the `nodes` directory in the userDir to find local node files. + * The following property can be used to specify an additional directory to scan. + */ + //nodesDir: '/home/nol/.node-red/nodes', + +/******************************************************************************* + * Security + * - adminAuth + * - https + * - httpsRefreshInterval + * - requireHttps + * - httpNodeAuth + * - httpStaticAuth + ******************************************************************************/ + + /** To password protect the Node-RED editor and admin API, the following + * property can be used. See http://nodered.org/docs/security.html for details. + */ + //adminAuth: { + // type: "credentials", + // users: [{ + // username: "admin", + // password: "$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN.", + // permissions: "*" + // }] + //}, + + /** The following property can be used to enable HTTPS + * This property can be either an object, containing both a (private) key + * and a (public) certificate, or a function that returns such an object. + * See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener + * for details of its contents. + */ + + /** Option 1: static object */ + //https: { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + //}, + + /** Option 2: function that returns the HTTP configuration object */ + // https: function() { + // // This function should return the options object, or a Promise + // // that resolves to the options object + // return { + // key: require("fs").readFileSync('privkey.pem'), + // cert: require("fs").readFileSync('cert.pem') + // } + // }, + + /** If the `https` setting is a function, the following setting can be used + * to set how often, in hours, the function will be called. That can be used + * to refresh any certificates. + */ + //httpsRefreshInterval : 12, + + /** The following property can be used to cause insecure HTTP connections to + * be redirected to HTTPS. + */ + //requireHttps: true, + + /** To password protect the node-defined HTTP endpoints (httpNodeRoot), + * including node-red-dashboard, or the static content (httpStatic), the + * following properties can be used. + * The `pass` field is a bcrypt hash of the password. + * See http://nodered.org/docs/security.html#generating-the-password-hash + */ + //httpNodeAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + //httpStaticAuth: {user:"user",pass:"$2a$08$zZWtXTja0fB1pzD4sHCMyOCMYz2Z6dNbM6tl8sJogENOMcxWV9DN."}, + +/******************************************************************************* + * Server Settings + * - uiPort + * - uiHost + * - apiMaxLength + * - httpServerOptions + * - httpAdminRoot + * - httpAdminMiddleware + * - httpNodeRoot + * - httpNodeCors + * - httpNodeMiddleware + * - httpStatic + * - httpStaticRoot + ******************************************************************************/ + + /** the tcp port that the Node-RED web server is listening on */ + uiPort: process.env.PORT || 80, + + /** By default, the Node-RED UI accepts connections on all IPv4 interfaces. + * To listen on all IPv6 addresses, set uiHost to "::", + * The following property can be used to listen on a specific interface. For + * example, the following would only allow connections from the local machine. + */ + //uiHost: "127.0.0.1", + + /** The maximum size of HTTP request that will be accepted by the runtime api. + * Default: 5mb + */ + //apiMaxLength: '5mb', + + /** The following property can be used to pass custom options to the Express.js + * server used by Node-RED. For a full list of available options, refer + * to http://expressjs.com/en/api.html#app.settings.table + */ + //httpServerOptions: { }, + + /** By default, the Node-RED UI is available at http://localhost:1880/ + * The following property can be used to specify a different root path. + * If set to false, this is disabled. + */ + httpAdminRoot: '/editor', + + /** The following property can be used to add a custom middleware function + * in front of all admin http routes. For example, to set custom http + * headers. It can be a single function or an array of middleware functions. + */ + // httpAdminMiddleware: function(req,res,next) { + // // Set the X-Frame-Options header to limit where the editor + // // can be embedded + // //res.set('X-Frame-Options', 'sameorigin'); + // next(); + // }, + + + /** Some nodes, such as HTTP In, can be used to listen for incoming http requests. + * By default, these are served relative to '/'. The following property + * can be used to specifiy a different root path. If set to false, this is + * disabled. + */ + //httpNodeRoot: '/red-nodes', + + /** The following property can be used to configure cross-origin resource sharing + * in the HTTP nodes. + * See https://github.com/troygoode/node-cors#configuration-options for + * details on its contents. The following is a basic permissive set of options: + */ + //httpNodeCors: { + // origin: "*", + // methods: "GET,PUT,POST,DELETE" + //}, + + /** If you need to set an http proxy please set an environment variable + * called http_proxy (or HTTP_PROXY) outside of Node-RED in the operating system. + * For example - http_proxy=http://myproxy.com:8080 + * (Setting it here will have no effect) + * You may also specify no_proxy (or NO_PROXY) to supply a comma separated + * list of domains to not proxy, eg - no_proxy=.acme.co,.acme.co.uk + */ + + /** The following property can be used to add a custom middleware function + * in front of all http in nodes. This allows custom authentication to be + * applied to all http in nodes, or any other sort of common request processing. + * It can be a single function or an array of middleware functions. + */ + //httpNodeMiddleware: function(req,res,next) { + // // Handle/reject the request, or pass it on to the http in node by calling next(); + // // Optionally skip our rawBodyParser by setting this to true; + // //req.skipRawBodyParser = true; + // next(); + //}, + + /** When httpAdminRoot is used to move the UI to a different root path, the + * following property can be used to identify a directory of static content + * that should be served at http://localhost:1880/. + * When httpStaticRoot is set differently to httpAdminRoot, there is no need + * to move httpAdminRoot + */ + httpStatic: '/home/pi/OpenScan/', + + //httpStatic: '/home/nol/node-red-static/', //single static source + /* OR multiple static sources can be created using an array of objects... */ + //httpStatic: [ + // {path: '/home/nol/pics/', root: "/img/"}, + // {path: '/home/nol/reports/', root: "/doc/"}, + //], + + /** + * All static routes will be appended to httpStaticRoot + * e.g. if httpStatic = "/home/nol/docs" and httpStaticRoot = "/static/" + * then "/home/nol/docs" will be served at "/static/" + * e.g. if httpStatic = [{path: '/home/nol/pics/', root: "/img/"}] + * and httpStaticRoot = "/static/" + * then "/home/nol/pics/" will be served at "/static/img/" + */ + //httpStaticRoot: '/static/', + +/******************************************************************************* + * Runtime Settings + * - lang + * - logging + * - contextStorage + * - exportGlobalContextKeys + * - externalModules + ******************************************************************************/ + + /** Uncomment the following to run node-red in your preferred language. + * Available languages include: en-US (default), ja, de, zh-CN, zh-TW, ru, ko + * Some languages are more complete than others. + */ + // lang: "de", + + /** Configure the logging output */ + logging: { + /** Only console logging is currently supported */ + console: { + /** Level of logging to be recorded. Options are: + * fatal - only those errors which make the application unusable should be recorded + * error - record errors which are deemed fatal for a particular request + fatal errors + * warn - record problems which are non fatal + errors + fatal errors + * info - record information about the general running of the application + warn + error + fatal errors + * debug - record information which is more verbose than info + info + warn + error + fatal errors + * trace - record very detailed logging + debug + info + warn + error + fatal errors + * off - turn off all logging (doesn't affect metrics or audit) + */ + level: "info", + /** Whether or not to include metric events in the log output */ + metrics: false, + /** Whether or not to include audit events in the log output */ + audit: false + } + }, + + /** Context Storage + * The following property can be used to enable context storage. The configuration + * provided here will enable file-based context that flushes to disk every 30 seconds. + * Refer to the documentation for further options: https://nodered.org/docs/api/context/ + */ + //contextStorage: { + // default: { + // module:"localfilesystem" + // }, + //}, + + /** `global.keys()` returns a list of all properties set in global context. + * This allows them to be displayed in the Context Sidebar within the editor. + * In some circumstances it is not desirable to expose them to the editor. The + * following property can be used to hide any property set in `functionGlobalContext` + * from being list by `global.keys()`. + * By default, the property is set to false to avoid accidental exposure of + * their values. Setting this to true will cause the keys to be listed. + */ + exportGlobalContextKeys: false, + + /** Configure how the runtime will handle external npm modules. + * This covers: + * - whether the editor will allow new node modules to be installed + * - whether nodes, such as the Function node are allowed to have their + * own dynamically configured dependencies. + * The allow/denyList options can be used to limit what modules the runtime + * will install/load. It can use '*' as a wildcard that matches anything. + */ + externalModules: { + // autoInstall: false, /** Whether the runtime will attempt to automatically install missing modules */ + // autoInstallRetry: 30, /** Interval, in seconds, between reinstall attempts */ + // palette: { /** Configuration for the Palette Manager */ + // allowInstall: true, /** Enable the Palette Manager in the editor */ + // allowUpload: true, /** Allow module tgz files to be uploaded and installed */ + // allowList: [], + // denyList: [] + // }, + // modules: { /** Configuration for node-specified modules */ + // allowInstall: true, + // allowList: [], + // denyList: [] + // } + }, + + +/******************************************************************************* + * Editor Settings + * - disableEditor + * - editorTheme + ******************************************************************************/ + + /** The following property can be used to disable the editor. The admin API + * is not affected by this option. To disable both the editor and the admin + * API, use either the httpRoot or httpAdminRoot properties + */ + //disableEditor: false, + + /** Customising the editor + * See https://nodered.org/docs/user-guide/runtime/configuration#editor-themes + * for all available options. + */ + editorTheme: { + /** The following property can be used to set a custom theme for the editor. + * See https://github.com/node-red-contrib-themes/theme-collection for + * a collection of themes to chose from. + */ + //theme: "", + palette: { + /** The following property can be used to order the categories in the editor + * palette. If a node's category is not in the list, the category will get + * added to the end of the palette. + * If not set, the following default order is used: + */ + //categories: ['subflows', 'common', 'function', 'network', 'sequence', 'parser', 'storage'], + }, + projects: { + /** To enable the Projects feature, set this value to true */ + enabled: false, + workflow: { + /** Set the default projects workflow mode. + * - manual - you must manually commit changes + * - auto - changes are automatically committed + * This can be overridden per-user from the 'Git config' + * section of 'User Settings' within the editor + */ + mode: "manual" + } + }, + codeEditor: { + /** Select the text editor component used by the editor. + * As of Node-RED V3, this defaults to "monaco", but can be set to "ace" if desired + */ + lib: "monaco", + options: { + /** The follow options only apply if the editor is set to "monaco" + * + * theme - must match the file name of a theme in + * packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/theme + * e.g. "tomorrow-night", "upstream-sunburst", "github", "my-theme" + */ + theme: "vs", + /** other overrides can be set e.g. fontSize, fontFamily, fontLigatures etc. + * for the full list, see https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneEditorConstructionOptions.html + */ + //fontSize: 14, + //fontFamily: "Cascadia Code, Fira Code, Consolas, 'Courier New', monospace", + //fontLigatures: true, + } + } + }, + +/******************************************************************************* + * Node Settings + * - fileWorkingDirectory + * - functionGlobalContext + * - functionExternalModules + * - nodeMessageBufferMaxLength + * - ui (for use with Node-RED Dashboard) + * - debugUseColors + * - debugMaxLength + * - execMaxBufferSize + * - httpRequestTimeout + * - mqttReconnectTime + * - serialReconnectTime + * - socketReconnectTime + * - socketTimeout + * - tcpMsgQueueSize + * - inboundWebSocketTimeout + * - tlsConfigDisableLocalFiles + * - webSocketNodeVerifyClient + ******************************************************************************/ + + /** The working directory to handle relative file paths from within the File nodes + * defaults to the working directory of the Node-RED process. + */ + //fileWorkingDirectory: "", + + /** Allow the Function node to load additional npm modules directly */ + functionExternalModules: true, + + /** The following property can be used to set predefined values in Global Context. + * This allows extra node modules to be made available with in Function node. + * For example, the following: + * functionGlobalContext: { os:require('os') } + * will allow the `os` module to be accessed in a Function node using: + * global.get("os") + */ +// functionGlobalContext: { + // os:require('os'), + // }, +functionGlobalContext: { // enables and pre-populates the context.global variable + os:require('os'), + path:require('path'), + fs:require('fs') + }, + /** The maximum number of messages nodes will buffer internally as part of their + * operation. This applies across a range of nodes that operate on message sequences. + * defaults to no limit. A value of 0 also means no limit is applied. + */ + //nodeMessageBufferMaxLength: 0, + + /** If you installed the optional node-red-dashboard you can set it's path + * relative to httpNodeRoot + * Other optional properties include + * readOnly:{boolean}, + * middleware:{function or array}, (req,res,next) - http middleware + * ioMiddleware:{function or array}, (socket,next) - socket.io middleware + */ + ui: { path: "" }, + + /** Colourise the console output of the debug node */ + //debugUseColors: true, + + /** The maximum length, in characters, of any message sent to the debug sidebar tab */ + debugMaxLength: 1000, + + /** Maximum buffer size for the exec node. Defaults to 10Mb */ + //execMaxBufferSize: 10000000, + + /** Timeout in milliseconds for HTTP request connections. Defaults to 120s */ + //httpRequestTimeout: 120000, + + /** Retry time in milliseconds for MQTT connections */ + mqttReconnectTime: 15000, + + /** Retry time in milliseconds for Serial port connections */ + serialReconnectTime: 15000, + + /** Retry time in milliseconds for TCP socket connections */ + //socketReconnectTime: 10000, + + /** Timeout in milliseconds for TCP server socket connections. Defaults to no timeout */ + //socketTimeout: 120000, + + /** Maximum number of messages to wait in queue while attempting to connect to TCP socket + * defaults to 1000 + */ + //tcpMsgQueueSize: 2000, + + /** Timeout in milliseconds for inbound WebSocket connections that do not + * match any configured node. Defaults to 5000 + */ + //inboundWebSocketTimeout: 5000, + + /** To disable the option for using local files for storing keys and + * certificates in the TLS configuration node, set this to true. + */ + //tlsConfigDisableLocalFiles: true, + + /** The following property can be used to verify websocket connection attempts. + * This allows, for example, the HTTP request headers to be checked to ensure + * they include valid authentication information. + */ + //webSocketNodeVerifyClient: function(info) { + // /** 'info' has three properties: + // * - origin : the value in the Origin header + // * - req : the HTTP request + // * - secure : true if req.connection.authorized or req.connection.encrypted is set + // * + // * The function should return true if the connection should be accepted, false otherwise. + // * + // * Alternatively, if this function is defined to accept a second argument, callback, + // * it can be used to verify the client asynchronously. + // * The callback takes three arguments: + // * - result : boolean, whether to accept the connection or not + // * - code : if result is false, the HTTP error status to return + // * - reason: if result is false, the HTTP reason string to return + // */ + //}, +} diff --git a/update/update.json b/update/update.json index 40fcdb3..22e0132 100644 --- a/update/update.json +++ b/update/update.json @@ -1,140 +1,84 @@ { - "mini": { + "stable": { "1": { - "src": "mini/fla.py", + "src": "stable/fla.py", "dst": "/home/pi/OpenScan/files/fla.py", - "filesize": 3910 + "filesize": 13012 }, "2": { - "src": "mini/Arducam.py", - "dst": "/usr/lib/python3/dist-packages/Arducam.py", - "filesize": 6154 - }, - "3": { - "src": "mini/OpenScan.py", + "src": "stable/OpenScan.py", "dst": "/usr/lib/python3/dist-packages/OpenScan.py", - "filesize": 5864 - }, - "4": { - "src": "mini/config.txt", - "dst": "/boot/config.txt", - "filesize": 2196 - }, - "5": { - "src": "mini/flows.json", - "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", - "filesize": 178895 - }, - "6": { - "src": "mini/settings.js", - "dst": "/root/.node-red/settings.js", - "filesize": 20321 - }, - "7": { - "src": "files/logo2.jpg", - "dst": "/home/pi/OpenScan/files/logo.jpg", - "filesize": 582519 - } - }, - "main": { - "1": { - "src": "main/fla.py", - "dst": "/home/pi/OpenScan/files/fla.py", - "filesize": 5366 - }, - "2": { - "src": "main/Arducam.py", - "dst": "/usr/lib/python3/dist-packages/Arducam.py", - "filesize": 6154 + "filesize": 10253 }, "3": { - "src": "main/OpenScan.py", - "dst": "/usr/lib/python3/dist-packages/OpenScan.py", - "filesize": 6161 + "src": "stable/config.txt", + "dst": "/boot/config.txt", + "filesize": 2185 }, "4": { - "src": "main/config.txt", - "dst": "/boot/config.txt", - "filesize": 2179 + "src": "stable/flows.json.tmpl", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json.tmpl", + "filesize": 325625 }, "5": { - "src": "main/flows.json", - "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", - "filesize": 350544 - }, - "6": { - "src": "main/settings.js", + "src": "stable/settings.js", "dst": "/root/.node-red/settings.js", - "filesize": 20321 - }, - "7": { - "src": "files/logo.jpg", - "dst": "/home/pi/OpenScan/files/logo.jpg", - "filesize": 582519 + "filesize": 21248 } }, + "beta": { "1": { "src": "beta/fla.py", "dst": "/home/pi/OpenScan/files/fla.py", - "filesize": 5366 + "filesize": 13012 }, "2": { - "src": "beta/Arducam.py", - "dst": "/usr/lib/python3/dist-packages/Arducam.py", - "filesize": 6154 - }, - "3": { "src": "beta/OpenScan.py", "dst": "/usr/lib/python3/dist-packages/OpenScan.py", - "filesize": 6443 + "filesize": 10253 }, - "4": { + "3": { "src": "beta/config.txt", "dst": "/boot/config.txt", - "filesize": 2179 + "filesize": 2185 }, - "5": { - "src": "beta/flows.json", - "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", - "filesize": 353390 + "4": { + "src": "beta/flows.json.tmpl", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json.tmpl", + "filesize": 337413 }, - "6": { + "5": { "src": "beta/settings.js", "dst": "/root/.node-red/settings.js", - "filesize": 20321 - }, - "7": { - "src": "files/logo.jpg", - "dst": "/home/pi/OpenScan/files/logo.jpg", - "filesize": 582519 + "filesize": 21248 } }, - "betaArdu": { + "meanwhile": { "1": { - "src": "betaArdu/fla.py", + "src": "meanwhile/fla.py", "dst": "/home/pi/OpenScan/files/fla.py", - "filesize": 12089 + "filesize": 13012 }, "2": { - "src": "betaArdu/OpenScan.py", + "src": "meanwhile/OpenScan.py", "dst": "/usr/lib/python3/dist-packages/OpenScan.py", - "filesize": 10060 + "filesize": 10322 }, "3": { - "src": "betaArdu/config.txt", + "src": "meanwhile/config.txt", "dst": "/boot/config.txt", "filesize": 2185 }, "4": { - "src": "betaArdu/flows.json", - "dst": "/home/pi/OpenScan/settings/.node-red/flows.json", - "filesize": 310044 + "src": "meanwhile/flows.json.tmpl", + "dst": "/home/pi/OpenScan/settings/.node-red/flows.json.tmpl", + "filesize": 340275 }, "5": { - "src": "betaArdu/settings.js", + "src": "meanwhile/settings.js", "dst": "/root/.node-red/settings.js", - "filesize": 21199 + "filesize": 21248 } } } \ No newline at end of file