Octoprint Plugin Development - HTU21D temp sensor

Hi all,

it is my first time in this community, and i've signed up because i'm having so struggling with the development of an octoprint plugins, so i hope some of you could solve my problem.

I'm studying python since about 3 days so excuse for my scarying way to code.

I just want to create a basic graphical environment to control a fan that cool down my 3D printer enclosure with an HTU21D probe. After some try i've a fully working script with some labels, buttons and other stuff.
So this is the problem, i'm following the tutorial on the website to create the plugin directly on my raspberry pi3 but i'm stucked at the installation point, i'm proceeding in this way:

  • source ~/oprint/bin/activate
  • pip install "cookiecutter>=1.4,<1.7"
  • octoprint dev plugin:new OctoFan
  • setting some name for the following fields:
    plugin_package [octoprint_helloworld]: OctoFan-pack
    plugin_name [OctoPrint-Helloworld]: OctoFan
    repo_name [OctoPrint-Helloworld]:
    full_name [You]: My Name
    email [you@example.com]: you@somewhere.net
    github_username [you]: yourGithubName
    plugin_version [0.1.0]: 1.0.0
    plugin_description [TODO]: A quick simple fan control for enclosure...
    plugin_license [AGPLv3]:
    plugin_homepage []:
    plugin_source []:
    plugin_installurl []:
  • cd /../OctoFan
  • inside of this folder deleting Extras, translation, static and templates folders
  • now i place my own python script in the folder and renaming it as _ init _.py
  • python setup.py develop
  • octoprint dev plugin:install
  • now i restart octoprint:
  • sudo service octoprint restart
  • sudo service octoprint stop
  • octoprint serve

and this is what i get:

2020-03-11 17:17:01,476 - octoprint.plugin.core - ERROR - Error loading plugin OctoFan
Traceback (most recent call last):
  File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/plugin/core.py", line 863, in _import_plugin
    instance = imp.load_module(module_name, f, filename, description)
  File "/home/pi/oprint/local/lib/python2.7/site-packages/OctoPrint_Octofan-1.0.0-py2.7.egg/octoprint_OctoFan/__init__.py", line 11, in <module>
    import htu21d.htu21d as htu
ImportError: No module named htu21d.htu21d
2020-03-11 17:17:01,501 - octoprint.plugin.core - ERROR - Error loading plugin OctoFan
Traceback (most recent call last):
  File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/plugin/core.py", line 863, in _import_plugin
    instance = imp.load_module(module_name, f, filename, description)
  File "/home/pi/oprint/local/lib/python2.7/site-packages/OctoPrint_Octofan-1.0.0-py2.7.egg/octoprint_OctoFan/__init__.py", line 11, in <module>
    import htu21d.htu21d as htu
ImportError: No module named htu21d.htu21d
2020-03-11 17:17:01,527 - octoprint.plugin.core - INFO - Found 20 plugin(s) providing 20 mixin implementations, 31 hook handlers
2020-03-11 17:17:01,886 - octoprint.server.heartbeat - INFO - Starting server heartbeat, 900.0s interval

it seems that the library htu21d that i've used is the reason of my problems

this is my code:

# -*- coding: utf-8 -*-
#!/usr/bin/python

__plugin_name__ = "OctoFan"
__plugin_version__ = "1.0.0"
__plugin_description__ = "A simple enclosure fan control for our 3D printer with HTU21D probe"
__plugin_pythoncompat__ = "2.7"


import Tkinter as tk
import RPi.GPIO as GPIO
import time, os, sys
import htu21d.htu21d as htu

fanpin = 17 #metodo di numerazione del chip, equivale all'11 del metodo board
temp_address = 0x40
bus_num = 1
temp_threshold_radio_button = 33 #°C
tracking_var  = False
sensor = htu.HTU21D()
status_fan = "Ventola OFF"
temp2show = " "
humid2show = " "
temp_provvisoria_1 = " "
temp_provvisoria_2 = " "
humid_provvisoria_1 = " "
humid_provvisoria_2 = " "

GPIO.setmode(GPIO.BCM)
GPIO.setup(fanpin, GPIO.OUT)
GPIO.setwarnings(False)

def temp_read():
 temp_provvisoria_1 = float(sensor.read_temperature())
 temp_provvisoria_2 = round(temp_provvisoria_1, 2)
 temp2show = str(temp_provvisoria_2) + " °C"
 label_temp['text']=temp2show
 label_temp.after(500, temp_read)

def humid_read():
 humid_provvisoria_1 = float(sensor.read_humidity())
 humid_provvisoria_2 = round(humid_provvisoria_1)
 humid2show = str(humid_provvisoria_2) + " %"
 label_humid['text']=humid2show
 label_humid.after(500, humid_read)

def Ventola_ON():
 GPIO.output(fanpin, GPIO.HIGH)
 print("Ventola accesa manualmente")
 text_status['text'] = "Ventola ON"
 text_status['fg'] = "green"
 global tracking_var
 tracking_var = False

def Ventola_OFF():
 GPIO.output(fanpin, GPIO.LOW)
 print("Ventola spenta manualmente")
 text_status['text'] = "Ventola OFF"
 text_status['fg'] = "red"
 global tracking_var
 tracking_var = False

def venti_deg():
 global temp_threshold_radio_button
 temp_threshold_radio_button = 25
 print("soglia temperatura impostata a 25 °C")


def trenta_deg():
 global temp_threshold_radio_button
 temp_threshold_radio_button = 33
 print("soglia temperatura impostata a 33 °C")


def Ventola_AUTO(toggle=False):
    global tracking_var
    if toggle:
        if tracking_var:
            tracking_var = False
        else:
            tracking_var = True

    if tracking_var:
        if temp_provvisoria_2 > temp_threshold_radio_button:
             print("Soglia temperatura superata, accendo ventola enclosure")
             GPIO.output(fanpin, GPIO.HIGH)
             #status_fan("Ventola ON")
             text_status['text'] = "Ventola ON"
             text_status['fg'] = "green"

        else:
             print("Temperatura sotto la soglia, ventola spenta")
             GPIO.output(fanpin, GPIO.LOW)
             #status_fan("Ventola OFF")
             text_status['text'] = "Ventola OFF"
             text_status['fg'] = "red"

        main_window.after(1000, Ventola_AUTO)



#finestra sul quale ancorare i widget
main_window = tk.Tk()
main_window.title("OctoFan")
main_window.geometry("500x300")
main_window.grid_columnconfigure(0, weight=1)

#cornice per il valore temperatura
label_frame_temp = tk.LabelFrame(main_window, text="Temperatura")
label_frame_temp.grid(row=0, column=0, padx=10, pady=10, sticky="N")

#etichetta per il valore temperatura
label_temp = tk.Label(label_frame_temp, text=temp2show)
label_temp.grid(row=0, column=0, padx=10, pady=10, sticky="N")

#cornice per umidità 
label_frame_humid = tk.LabelFrame(main_window, text="Umidità rel")
label_frame_humid.grid(row=0, column=3, padx=10, pady=10, sticky="N")

#etichetta per umidità 
label_humid = tk.Label(label_frame_humid, text=humid2show)
label_humid.grid(row=0, column=3, padx=10, pady=10, sticky="N")

#pulsante ventola on
fan_on = tk.Button(text="Ventola ON", fg="green", command=Ventola_ON)
fan_on.grid(row=1, column=0, padx=10, pady=10, sticky="N")

#pulsante ventola auto
fan_auto = tk.Button(text="Ventola AUTO", fg="blue", command=lambda: Ventola_AUTO(True))
fan_auto.grid(row=1, column=1, padx=10, pady=10, sticky="N")

#pulsante ventola off
fan_off = tk.Button(text="Ventola OFF", fg="red", command=Ventola_OFF)
fan_off.grid(row=1, column=3, padx=10, pady=10, sticky="E")

#cornice per checkbox
label_frame_threshold = tk.LabelFrame(main_window, text="Threshold Attivazione Ventola")
label_frame_threshold.grid(row=3, column=1, padx=10, pady=10)

#checkbox
temp_threshold = tk.IntVar()
temp_threshold.set(1)

#checkbox_1
temp_threshold_one = tk.Radiobutton(label_frame_threshold, text="25 C", variable=temp_threshold, value=0, command=venti_deg)
temp_threshold_one.grid(row=3, column=0, padx=10, pady=10, sticky="W")

#checkbox_2
temp_threshold_two = tk.Radiobutton(label_frame_threshold, text="33 C", variable=temp_threshold, value=1, command=trenta_deg)
temp_threshold_two.grid(row=3, column=1, padx=10, pady=10, sticky="W")

#cornice testo ventola
label_frame_fan = tk.LabelFrame(main_window, text="Status Ventola")
label_frame_fan.grid(row=0, column=1, padx=10, pady=10, sticky="N")

#testo ventola
text_status = tk.Label(label_frame_fan, text=status_fan, fg="red")
text_status.grid(row=0, column=1, padx=10, pady=10, sticky="N")


label_temp.after(500, temp_read)
label_humid.after(500, humid_read)

main_window.mainloop()

Thanks all for your help

Looks like you need to install the htu21d module in order to be able to import it into your code. I'm not familiar with that module but try this

cd ~/oprint/bin/
pip install htu21d

I think I would suggest teaching this version...

source ~/oprint/bin/activate
pip install htu21d

And this shebang is a little dangerous in that it's using the global python rather than the one that's in the ~/oprint/lib/whatever for the virtual environment.

I've tryed that, and after a fresh installation of my plugin, and a sudo service octoprint stop and octoprint serve i get this

| !OctoPrint-Octofan (1.0.0) = /home/pi/oprint/local/lib/python2.7/site-packages/OctoPrint                                                                                                _Octofan-1.0.0-py2.7.egg/octoprint_OctoFan

but after a restart of the pi i keep get the previous error :disappointed_relieved:

Tryed also this command but:

Could not find a version that satisfies the requirement htu21d (from versions: )
No matching distribution found for htu21d

That's your problem. You need to find a module that is available...

Tryed to install that by pip install htu21df and get Package 'mock' requires a different Python: 2.7.13 not in '>=3.6' so i tryed pip install mock but i have the same error.

Now my question is, could i write my script comptatible wiith python3 or not? If yes i could perform pip3 install htu... but i think i can't because octorpint uses python2.7 (?)

Really thank you for that, but i can't find a package that work :roll_eyes:

Yeah... we're in the period now where lots of authors just aren't supporting Py2 anymore. Out-of-the-box, the OctoPi-imaged IMG file is Py2. If you're a developer like myself, you've replaced the Py2 virtual environment with Py3 for your work... so that would work then in this case.

Go back to PyPi and see if there's one that will work with Py2.

Yes, Sad :expressionless:

But i think that i've partially solved the problem, i found a script on the web that did not use any libraries and adding my parts of code now after installing the new script i do not have the previous error, BUT another one, maybe caused by tkinter?

2020-03-12 23:27:48,908 - octoprint.plugin.core - ERROR - Error loading plugin EncloFan
Traceback (most recent call last):
  File "/home/pi/oprint/local/lib/python2.7/site-packages/octoprint/plugin/core.py", line 863, in _import_plugin
    instance = imp.load_module(module_name, f, filename, description)
  File "/home/pi/EncloFan/octoprint_EncloFan/__init__.py", line 213, in <module>
    main_window = tk.Tk()
  File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1823, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
TclError: no display name and no $DISPLAY environment variable

Any idea? Thank for the help :facepunch:
just another last chance to get it work :sob: :joy:

If you're using matplotlib in all this, then you probably want to... matplotlib.use('Agg') in your code.

I never used matplotlib in my code... i think i have to give up on the project :disappointed:

thank for your help

The basic error it threw means "you're trying to send output to a device that doesn't exist". So it may be necessary to divert something using an environment variable called DISPLAY which is set to... something else.

You're right.. i need to find on the web something that could help me on that.

thank you for all your help :v: :v:

1 Like