I'm new to OpenWrt but I have about a year of self-project (college final project, to be exact) experience using Linux in Raspberry Pi.
Have anyone here used I2C OLED SSD1306 on Orange Pi R1 Plus LTS with OpenWrt? I'm stuck now with the problem of enabling it.
I use OpenWrt 21.02.2, r16495-bf0c965af0.
Here's what I have tried: I used this library: https://github.com/karabek/OrangePi-OLED, and I tried to detect the i2c on bus 0 and 1 to get the device address, and I ran the demo file from the library. I expected the device to be able to run the i2c device on the detected port and address correctly.
When I tried to detect the i2c on bus 0 and 1, here's the output:
root#OpenWrt:~# i2cdetect -y 0
Error: Could not open file `/dev/i2c-0' or `/dev/i2c/0': No such file or directory
root#OpenWrt:~# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
And then I modified the demo file from the library:
device = ssd1306(port=1, address=0x18)
And I run it. Here's what I got
root#OpenWrt:/mnt/OrangePi-OLED/examples# python3 demo.py
Traceback (most recent call last):
File "/mnt/OrangePi-OLED/examples/demo.py", line 11, in <module>
device = ssd1306(port=1, address=0x18)
File "/usr/lib/python3.9/site-packages/oled/device.py", line 163, in __init__
self.command(
File "/usr/lib/python3.9/site-packages/oled/device.py", line 73, in command
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
OSError: [Errno 16] Resource busy
I suspect this is because of the bus 0 is not enabled yet, as here is what the documentation says
Orange Pi R1 Plus LTS Documentation
But the OpenWrt version I'm using doesn't have the boot folder.
What is the solution?
Also, if it turns out I can't use I2C, what display should I use? Can I use SPI TFT IPS or UART display?
I am working with a BPi and I would like to read an CAN to I2C module connected to the SCL and SCA pins of the BPi.
When I try to detect the module, it seems to work fine, as i run i2cdetect -y 0 and the module with address 0x25 appears as follows:
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- 25 -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- UU -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Then, I try the i2cget -y 0 0x25 0 command, and something strange happens. I tried it once, and it returned 0x00, and after that, every time I run the same command, it pops up an error Error: Read failed.
Just as additional information, I am using a LoganLabs I2C-CAN module and a BPi with the Raspbian Stretch OS. I have the CAN module connected to a kvaser in which a CAN message is sent, so I think I should be able to read something with this commands.
I am trying to run this commands on the command window as a debbuging process, as I t also tried with the following code above, which simply returns "None".
from smbus2 import SMbus, i2c_msg
import time
address=25
def func1():
lect=i2c_msg.read(address,0)
while True:
lecture1=func1()
print(lecture1)
time.sleep(1)
'''
It returns: None
'''
I'm trying to get the following code working after battling with an smbus2 error i now find i have the following error and can't find how to fix it.
I know the sensor is working because if I run bme280.py from http://www.raspberrypi-spy.co.uk/ that works ok.
So my error is:
pi#wpi:~/weather $ python bme280_sensor.py
Traceback (most recent call last):
File "bme280_sensor.py", line 9, in <module>
bme280.load_calibration_params(bus, address)
AttributeError: 'module' object has no attribute 'load_calibration_params'
i2detect
pi#wpi:~/weather $ i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- 76 --
Code not working: from https://pypi.org/project/RPi.bme280/
import smbus2
import bme280
port = 1
address = 0x76
bus = smbus2.SMBus(port)
calibration_params = bme280.load_calibration_params(bus, address)
# the sample method will take a single reading and return a
# compensated_reading object
data = bme280.sample(bus, address, calibration_params)
# the compensated_reading class has the following attributes
print(data.id)
print(data.timestamp)
print(data.temperature)
print(data.pressure)
print(data.humidity)
# there is a handy string representation too
print(data)
Found my issue posting it here in case any other newbies have the same issue!
I had a file called bme280.py in the same folder so it was loading that file instead of the correct bme280 library.
The solution was simply to rename that file.
Mine worked after I installed RPi.bme280
$ sudo pip3 install RPi.bme280
This is from the bme280 documentation:
https://github.com/rm-hull/bme280
This is not my code :
import Data.Monoid (Endo (..), appEndo)
import Data.Foldable (foldMap)
-- | chainEndos chain a list of endomorphisms to create a new one
-- Point-free version is feasible and redable.
-- Level: Easy
--
-- Examples:
--
-- >>> chainEndos [(+1),(*3)] 2
-- 7
-- >>> chainEndos [('h':),('e':)] "llo"
-- "hello"
--
-- >>> chainEndos [] (12 :: Int)
-- 12
--
chainEndos :: [a->a] -> a -> a
chainEndos = appEndo . foldMap Endo
chainEndos' :: [a->a] -> a -> a
chainEndos' = foldr (.) id
main = print $ chainEndos [('h':),('e':)] "llo"
I would like to run this in the Haskell IDE : http://www.haskell.org/platform/
But WinGhci offers just a repl like structure ? How can I load this as haskell file and run it ?
Save it to file, then
File -> Load
that's all, after it you can call main
The example below defines a snaplet to bind nicEditor to textarea. The following questions are not only related to the example below, but probably they are related to some other similar cases..
Can a newbie follow the instructions below (how to clarify)?
How to make the example use less steps or otherwise simpler? (Is it possible with approximately the same content as below?)
This used interpreted splice. If possible, should a snaplet provide compiled splices, too?
A snaplet probably could give a default handler or couple of handlers to typical situations. And handlers could be defined in the "SnapNic.hs" below. Some callback mechanism to users, then?
--
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE OverloadedStrings #-}
------------------------------------------------------------------------------
-- | This module defines nicEditor snaplet, just a short example to show,
-- how snaplets can be defined together with splices.
-- License: BSD3.
-- Here are hopefully easy instructions, how to use or try:
--
-- 1. Make a directory, we'll use "netry" below, go there.
-- Initialize a project, e.g. "snap init default".
-- 2. Copy this file to netry/src-directory as SnapNic.hs.
-- 3. Add "import SnapNic" to Site.hs and to Application.hs
-- 4. Add ", _niced :: Snaplet Nicsnap" to data App in Application.hs
--
-- 5. Add "n <- nestSnaplet "niced" niced nicsnapInit" to
-- app :: SnapletInit App App in Site.hs.
-- 6. Add "addNicEditSplices n" to the same function as in step 5.
-- 7. Change the return-line of the same function as in step 5:
-- "return $ App h s a n"
-- that is, add "n" into the end. We need this because of step 4.
--
-- 8. Make route, e.g. ", ("/netext", with auth handleNEtext)" to
-- routes-function in Site.hs
--
-- 9. And then add handler into Site.hs:
-- handleNEtext :: Handler App v ()
-- handleNEtext = method GET handleForm <|> method POST handleFormSubmit
-- where
-- handleForm = render "textedit"
-- handleFormSubmit = do
-- p <- getParam "ots"
-- writeText "Submitting text from textarea...\n"
-- writeText (T.pack (show p))
--
-- 10. Last, add the following 2 templates to "netry/snaplets/heist/templates".
-- (This could be made simpler, but this works as an example of apply-tag.)
-- textedit.tpl:
-- <apply template="base">
-- <apply template="_textedit" />
-- </apply>
-- _textedit.tpl:
-- <h2>Your nic editor</h2>
-- <form method="post" action="netext">
-- <neTA/>
-- <button name="ne" value="ne" type="Submit">Send text</button>
-- </form>
-- <neScript/>
--
-- 11. Compile everything "cabal install -fdevelopment". After that,
-- if everything compiled, "netry -p 8000", start your browser and go
-- to "localhost:8000/netext".
--
-- TODO! This could use the config-files at least for some parameters, and more
-- tags,please. Tags could use some attributes (for example, size parameters
-- could be given as attributes of tags)...
--
module SnapNic
( Nicsnap (..)
, nicsnapInit
, addNicEditSplices
) where
------------------------------------------------------------------------------
import Control.Lens (makeLenses, view, (^.))
import qualified Data.Text as T (Text, append, pack)
import Data.Maybe (fromJust, fromMaybe)
import Snap.Core (MonadSnap)
import Snap.Snaplet (Snaplet
, makeSnaplet
, snapletValue
, SnapletInit
, Initializer
)
import Snap.Snaplet.Heist (HasHeist, addSplices)
import qualified Text.XmlHtml as X (Node (Element, TextNode))
import qualified Heist.Interpreted as I (Splice)
------------------------------------------------------------------------------
-- | Nicsnap has fields that can be used to set some basic properties.
-- The editor can have a title and its size can be set. Javascript can be
-- local or remote.
data Nicsnap = Nicsnap
{ _nicsnap :: T.Text -- title
, _areaSize :: (Int,Int) -- rows, cols
, _areaRef :: T.Text -- how to apply nicEditors?
-- (This may not be sufficient in order to refer in some other way, TODO!)
, _localR :: Maybe T.Text -- local route to nicEdit.js
, _webR :: T.Text -- route to nicEdit's javascript source.
}
makeLenses ''Nicsnap -- makes webR and other lenses
------------------------------------------------------------------------------
-- | Configurations are given here. This could use config-files...
-- What other things to configure?
-- If you want to make a local copy of the nicEdit, then add a static route
-- to the "routes"-function.
nicsnapInit :: SnapletInit b Nicsnap
nicsnapInit = makeSnaplet "nicsnap" "NicEditor snaplet " Nothing $ do
let m = "Nic editor title"
aS = (20,80)::(Int,Int) -- rows, cols
aR = "nicEditors.allTextAreas" -- TODO! We need to be able to tell,
-- which textareas have editors in a page.
lR = Nothing
-- lR = Just "/nicEdit.js"
-- If localR is nothing, then webR is used with the following addr.
wR = "http://js.nicedit.com/nicEdit-latest.js"
return $ Nicsnap m aS aR lR wR
------------------------------------------------------------------------------
-- | Internal, this makes the script-tag.
-- Input could be e.g. txt = "/nicEdit.js"
srcElem :: T.Text -> X.Node
srcElem txt = X.Element "script"
[("src",txt),("type","text/javascript")] []
-- | Internal, this makes the script-tag. At the moment this changes all
-- textareas to niceditors, if the example input below is used. TODO!...
-- Input could be e.g. txt = "nicEditors.allTextAreas"
srcOnLoad :: T.Text -> X.Node
srcOnLoad txt = X.Element "script" [("type","text/javascript")]
[X.TextNode (T.append (T.append "bkLib.onDomLoaded(" txt) ");")]
-- | Internal, used to define "divs", where we give a label and size to
-- textarea. Also ids and names.
-- TODO! ids and names could be parameters.
divLabelTX :: T.Text -> T.Text -> T.Text -> X.Node
divLabelTX title r c = X.Element "div" [("class", "required")]
[ X.Element "label" [("for","ots")]
[X.TextNode title]
, X.Element "textarea"
[("id","ots"), ("name","ots"), ("cols",c), ("rows",r)]
[X.TextNode " "]
]
-- | Internal, this can be used in splice-definition.
-- TODO! ids and names could be parameters, too.
nicTextAreaAdd :: MonadSnap m => T.Text -> (Int,Int) -> I.Splice m
nicTextAreaAdd title (r,c) = return [divLabelTX
title
(T.pack . show $ r)
(T.pack . show $ c)]
-- | Add script-tags to web page with splice that tell, what javascript
-- library to use...
nicEditAdd :: MonadSnap m => T.Text -> T.Text -> I.Splice m
nicEditAdd src edElems = return (srcElem src : [srcOnLoad edElems])
------------------------------------------------------------------------------
-- | Get the route to the javascript library that is applied (either local
-- library or construct a link to a web address).
nicRoute :: Nicsnap -> T.Text
nicRoute ns = let mlR = ns ^. localR in fromMaybe (ns ^. webR) mlR
------------------------------------------------------------------------------
-- | neTextAreaTag and neScripTag are used in addSplices to define the tags
-- to be used in templates.
-- What other tags could be useful? Maybe a way to add a nicEditor directly
-- with one or more button bind to it ("send", "clear", etc). TODO!
neTextAreaTag = "neTA" :: T.Text
neScriptTag = "neScript" :: T.Text
-- | Make the tags to be used in templates. At the moment, only the above
-- tags are defined.
addNicEditSplices :: HasHeist b => Snaplet Nicsnap -> Initializer b v ()
addNicEditSplices n = let m = view snapletValue n in addSplices
[(neTextAreaTag, nicTextAreaAdd (m ^. nicsnap) (m ^. areaSize))
,(neScriptTag, nicEditAdd (nicRoute m) (m ^. areaRef) )
]
------------------------------------------------------------------------------
I'm not a newbie, so I can't answer your first question, but I've got some thoughts and answers to some of the others. First of all, if you really want this to be a serious snaplet (either for instructional purposes or real use) you should probably make this into a cabal project. That would eliminate step 2 from your instructions. Next, snaplets can define their own routes. You can do that in your initializer by calling the addRoutes function. This would eliminate step 8. Snaplets can also provide their own filesystem resources that will be copied into any project that uses it. You could use this feature to eliminate step 10, as well as provide default config files. For more information on how to do this, look at the filesystem data and automatic installation section at the end of the snaplet tutorial.
Currently, snaplet-postgresql-simple is probably the best example on hackage of how to use most of the features that snaplets have to offer. If you want to make this a really robust general purpose snaplet for other people to use, then you should definitely include both interpreted and compiled splices. I recently added some new functions to the snap package that make it easier to write generic snaplets that automatically work in either compiled or interpreted splice mode. That code isn't on hackage yet, but I'll probably be releasing it soon.
I have also been working on another snaplet that makes much more comprehensive use of most of the features of the snaplet API. Unlike snaplet-postgresql-simple, this snaplet defines templates and splices. It is still under development, but already demonstrates most of the features. The remaining work will be mostly just polish and robustness.