Skip to content

Commit

Permalink
Fixed leds and updated documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
texx00 committed Jan 30, 2021
1 parent 3ce2834 commit f18286b
Show file tree
Hide file tree
Showing 17 changed files with 106 additions and 42 deletions.
Binary file added docs/images/control.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/drawing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/playlist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Installation troubleshooting

## pyserial errors

It may happen that the serial port is not working correctly.
In this case activate the environment, uninstall the "serial" and the "pyserial" modules and install again the "pyserial":
```
$> source env/bin/activate
(env) $> python3 -m pip uninstall serial pyserial
(env) $> python3 -m pip install pyserial
```

## "Serial not available. Will use fake device"

The previous message may appear on the command line while running the program.
This is a normal behaviour on the first run because it is necessary to select the serial device to connect from the UI.

Open your browser, put ip:5000 and open the settings page (button on the top right corner) and select the serial port and baudrate.

## After the update the browser is stuck on a gray/white page

When updating from one version to another, for the moment, it may happen that the software get stuck on old data.

To fix the problem:
* clear the cache of the browser

or
* in the browser console (google -> how to open "browser name" javascript console) run the command `localStorage.clear()`

Then reload the page
11 changes: 11 additions & 0 deletions docs/versions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Software versions and added features

## v0.2.1-alpha
* Some changes in the playlists and added a new "element" mechanics for the playlist:
* The playlist can contain elements: at the moment only the drawing and the custom_command elements are available... Soon will introduce more
* First test with leds. For the moment working with WS2812B and dimmable leds only
* Some important fixes found during the development of the other features

## v0.2-alpha
* React introduction
* The frontend has been reworked completely and now is based on React, Redux and Bootstrap
* The interface is not tested much, easy to find bugs

## v0.1-alpha
* Very first release
* This version is just a demo to show the software idea and to spread the word around.
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/SortableElements.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class SortableElements extends Component{

render(){
return <ReactSortable
distance={1}
animation={150}
ghostClass="sortable-ghost"
chosenClass="sortable-chosen"
Expand Down Expand Up @@ -71,8 +72,10 @@ class SortableElements extends Component{

return <ElementCard key={el.id}
handleUnmount={()=>this.removeElement(el.id)}
showCross={this.state.show_child_cross}>
showCross={this.state.show_child_cross}
onClick={()=>console.log("click2")}>
<ElementType element={el}
onClick={()=>console.log("click")}
onOptionsChange={(el) => this.props.onElementOptionsChange(el)}
hideOptions={this.props.hideOptions}/>
</ElementCard>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/structure/tabs/leds/Leds.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class LedsController extends Component{
handleColorChange(color){
this.setState({...this.state, color: color.hex});
this.background_ref.current.style.backgroundColor = color.hex;
leds_set_color(color.hsv);
leds_set_color(color.rgb);
}

render(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ class BasicElement extends Component{
}

handleClick(){
console.log("prova")
if (this.props.onClick) this.props.onClick();
if (!this.props.hideOptions === "true")
this.setState({...this.state, showModal: true });
Expand Down
20 changes: 6 additions & 14 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ The project is opensource under MIT license and thus anyone can help (there is s
![Main page](docs/images/preview.png)
![Playlist](docs/images/playlist.png)
![Drawing](docs/images/drawing.png)
![Manual](docs/images/control.png)

# Installation

Expand Down Expand Up @@ -108,17 +109,12 @@ To stop the server starting automatically use `$> python start.py -a=off`
Once the service is running it is possible to connect through a browser by typing the device ip address and connecting to the port 5000 like `192.168.1.15:5000`
If you are running on the local device you can also use `127.0.0.1:5000`

## Installation troubleshooting
# Installation troubleshooting

It may happen that the serial port is not working correctly.
In this case activate the environment, uninstall the "serial" and the "pyserial" modules and install again the "pyserial":
```
$> source env/bin/activate
(env) $> python3 -m pip uninstall serial pyserial
(env) $> python3 -m pip install pyserial
```
If you find problems during the installation check the [troubleshooting](/docs/troubleshooting.md) page

If you find any bug or problem please open an issue in the dedicated page.
**If you find any bug or problem please feel free to open an [issue](https://github.com/texx00/sandypi/issues) in the dedicated page.**
___

# Updates

Expand All @@ -142,11 +138,7 @@ $> source env/bin/activate
(env) $> install.bat
```

After the update it may be necessary to clear the browser cache.
It is also possible to use the following command in the browser console (google "javascript console browser_model"):
```
localStorage.clear()
```
If you have problems after the update check the [troubleshooting](/docs/troubleshooting.md) guide.

# Development and testing

Expand Down
2 changes: 2 additions & 0 deletions server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def base_static(filename):
from server.hw_controller.feeder import Feeder
from server.hw_controller.feeder_event_manager import FeederEventManager
from server.hw_controller.leds.leds_controller import LedsController
from server.hw_controller.leds.leds_driver import LedsDriver


# Initializes sockets emits
Expand All @@ -74,6 +75,7 @@ def base_static(filename):
app.qmanager = QueueManager(app, socketio)

app.leds_controller = LedsController(app)
app.leds_controller.start()

# Get lates commit short hash to use as a version to refresh cached files
sw_version = software_updates.get_commit_shash()
Expand Down
31 changes: 27 additions & 4 deletions server/hw_controller/leds/leds_controller.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
from server.utils import settings_utils
from server.hw_controller.leds.leds_driver import LedsDriver
from threading import Thread, Lock

class LedsController:
def __init__(self, app):
self.app = app
settings = settings_utils.load_settings()
dimensions = (settings["leds"]["width"], settings["leds"]["height"])
self.dimensions = None
self.update_settings(settings)
self._should_update = False
self.mutex = Lock()
# may have problems with the leds controller if self.driver.deinit or self.stop is not called on app shutdown

def start(self):
self._running = True
self._th = Thread(target = self._thf, daemon=True)
self._th.name = "leds_controller"
self._th.start()

def stop(self):
self._running = False

def _thf(self):
self.app.logger.error("Leds controller started")
while(self._running):
with self.mutex:
if (self._should_update):
self.driver.fill(self._color)
self._should_update = False
self.app.logger.error("test")
self.driver.deinit()

# sets a fixed color for the leds
def set_color(self, color_hsv):
self.app.logger.warn("Color")
self.driver.fill(self.driver.hsv2rgb(color_hsv[0], color_hsv[1], color_hsv[2]))
def set_color(self, color):
with self.mutex:
self._color = color
self._should_update = True

def start_animation(self, animation):
# TODO add animations picker:
Expand Down
24 changes: 10 additions & 14 deletions server/hw_controller/leds/leds_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ def __init__(self, dimensions):
raise ValueError("It is necessary to set a width and height for the leds frame")

# setting up leds
self.dimensions = dimensions
self.led_number = 2*(dimensions[0] + dimensions[1])
self.dimensions = (int(dimensions[0]), int(dimensions[1]))
self.led_number = 2*(self.dimensions[0] + self.dimensions[1])
self.leds = None

def use_dimmable(self, pin):
try:
if __name__ == "__main__":
if __name__ == "__main__": # in order to test the file directly
from libs.dimmable import Dimmable
else:
from server.hw_controller.leds.libs.dimmable import Dimmable
Expand All @@ -41,10 +41,11 @@ def use_WS2812B(self, pin):
# platform dependent imports
try:
if __name__ == "__main__":
from libs.WS2812B import WS2812B
from libs.WS2812B import WS2812B # in order to test the file directly
else:
from server.hw_controller.leds.libs.WS2812B import WS2812B
self.leds = WS2812B(int(self.led_number), pin)

self.leds = WS2812B(self.led_number, pin)
return True

except Exception as e:
Expand Down Expand Up @@ -79,20 +80,14 @@ def set_pixel(self, val, col):
def fill(self, color):
if self.is_ok():
if type(color) is list:
print("0", flush=True)
if len(color[0]) == 1: # check if the list contains lists or tuples with lenght 3
print(1, flush=True)
if len(color) == 3: # check if the list itself must be a color tuple
color = tuple(color)
print(2, flush=True)
else:
print(3, flush=True)
return False
else:
self.leds[0:len(color)] = color
print(4, flush=True)
return True
print(5, flush=True)
self.leds.fill(color)
return True
return False
Expand All @@ -107,15 +102,16 @@ def deinit(self):
self.leds.deinit()
self.leds = None



if __name__=="__main__":
ld = LedsDriver((30,20))
ld.use_WS2812B(18)
ld.white()
time.sleep(2)
for i in range(20):
ld.rainbow(i/200.0)
time.sleep(0.1)
time.sleep(2)
ld.white()
time.sleep(2)
ld.clear()
ld.clear()
ld.deinit()
4 changes: 4 additions & 0 deletions server/hw_controller/leds/libs/WS2812B.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ def __setitem__(self, key, value):

def deinit(self):
self.pixels.deinit()

if __name__ == "__main__":
leds = WS2812B(100,18)
leds.fill((255,255,255))
1 change: 0 additions & 1 deletion server/saves/saved_settings copy.json

This file was deleted.

2 changes: 1 addition & 1 deletion server/sockets_interface/socketio_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,4 @@ def queue_stop_drawing():
@socketio.on("leds_set_color")
def leds_set_color(data):
color = json.loads(data)
app.leds_controller.set_color((color["h"], color["s"], color["v"]))
app.leds_controller.set_color((color["r"], color["g"], color["b"]))
15 changes: 9 additions & 6 deletions server/utils/settings_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import logging
import platform
from netifaces import interfaces, ifaddresses, AF_INET
from deepmerge import always_merger

# Logging levels (see the documentation of the logging module for more details)
LINE_SENT = 6
Expand Down Expand Up @@ -37,16 +36,20 @@ def update_settings_file_version():
else:
old_settings = load_settings()
def_settings = ""
print(old_settings)
with open(defaults_path) as f:
def_settings = json.load(f)
print(def_settings)
new_settings = match_dict(old_settings, def_settings)
print(new_settings)
save_settings(new_settings)

def match_dict(mod_dict, ref_dict):
return always_merger.merge(ref_dict, mod_dict)
if type(ref_dict) is dict:
new_dict = dict(mod_dict)
for k in ref_dict.keys():
if not k in mod_dict:
new_dict[k] = match_dict(mod_dict[k], ref_dict[k])
return new_dict
else:
return ref_dict

# print the level of the logger selected
def print_level(level, logger_name):
Expand Down Expand Up @@ -91,7 +94,7 @@ def get_ip4_addresses():
print(get_ip4_addresses())
a = {"a":0, "b":{"c":2, "d":4}}
b = {"a":1, "b":{"c":1, "e":5}, "c":3}
c = match_dict(b,a)
c = match_dict(a,b)
print(a)
print(b)
print(c)

0 comments on commit f18286b

Please sign in to comment.