Custom Plugin Creation Help

Moderators: Gully, peteru

Post Reply
naigy
Apprentice
Posts: 61
Joined: Wed May 03, 2017 10:18

Custom Plugin Creation Help

Post by naigy » Sat Aug 05, 2017 15:39

Hi,

I am creating a basic plugin for implementing notifications from my Raspberry Pi / Arduino home automation through my Beyonwiz T4. As far as the coding on the Arduino / Pi side I am fine and have gone with the writing to a file on the T4 (/tmp/test) which then displays Text on screen with the related information from the file. Note: Arduino / Pi checks that the T4 is on and the current Activity (through Harmony API Hack) before posting the file.

What I need help on is the following

1. How do I make the plugin start automatically on bootup
2. How do I put the Main routine in a loop checking for the file (in the background). Currently when I run the plugin it checks immediately for the file and then seemingly the app closes (I want it to run the Main routine indefinitely. I did try a while loop but it appears to crash the T4. Would like to sort this before I sort point 1 so that if the plugin crashes at least I don't have issues with bootup whilst I get it all functional but if programs on a loop only works for autostart .
3. Lastly I want the message to display for a set time period and then disappear

The code I am using currently has been taken from IhadTutorial and modified to start to suit my needs

Code: Select all

# Ihad.tv enigma2-plugin tutorial 2010
# lesson 3
# by emanuel
from Screens.Screen import Screen
from Components.Label import Label
from Components.ActionMap import ActionMap
from Screens.MessageBox import MessageBox
from Plugins.Plugin import PluginDescriptor
import os
global msgx
###########################################################################

class CallMyMsg(Screen):
        skin = """
                <screen position="10,50" size="460,75" title="Home System Update" >
                        <widget name="myLabel" position="10,5" size="400,20" font="Regular;20"/>
                </screen>"""

        def __init__(self, session, args = 0):
                self.session = session
                Screen.__init__(self, session)

                self["myLabel"] = Label(_(msgx))
                self["myActionMap"] = ActionMap(["SetupActions"],
                {
                        "ok": self.myMsg,
                        "cancel": self.cancel
                }, -1)

        def callMyMsg(self, result):
                print "\n[CallMyMsg] checking result\n"
                if result:
                        print "\n[CallMyMsg] cancel\n"
                        self.close(None)
                else:
                        self.session.open(MessageBox,_("Ah, you like the Ihad plugin!\n;-)"), MessageBox.TYPE_INFO)

        def myMsg(self):
                print "\n[CallMyMsg] OK pressed \n"
                self.session.openWithCallback(self.callMyMsg, MessageBox, _("Do you want to exit the plugin?"), MessageBox.TYPE_YESNO)

        def cancel(self):
                print "\n[CallMyMsg] cancel\n"
                self.close(None)

###########################################################################

def main(session, **kwargs):
        global msgx
        if os.path.isfile('/tmp/test'):
                msgfile = open('/tmp/test')
                msgx = msgfile.read()
                msgfile.close()
                os.remove('/tmp/test')
                session.open(CallMyMsg)
###########################################################################


def Plugins(**kwargs):
        return PluginDescriptor(
                        name="00 Craig Test",
                        description="Adapted from IHADTutorial",
                        where = PluginDescriptor.WHERE_PLUGINMENU,
                        icon="../ihad_tut.png",
                        fnc=main)

Any pointers appreciated.

User avatar
MrQuade
Uber Wizard
Posts: 11844
Joined: Sun Jun 24, 2007 13:40
Location: Perth

Re: Custom Plugin Creation Help

Post by MrQuade » Sat Aug 05, 2017 16:14

You don't need a plugin to display messages on the T4 screen. The OpenWebIf has a nice little API feature to do just that.

https://dream.reichholf.net/e2web/#message

Code: Select all

http://beyonwizt4//web/message?text=&type=&timeout=&default=
Logitech Harmony Ultimate+Elite RCs
Beyonwiz T2/3/U4/V2, DP-S1 PVRs
Denon AVR-X3400h, LG OLED65C7T TV
QNAP TS-410 NAS, Centos File Server (Hosted under KVM)
Ubiquiti UniFi Managed LAN/WLAN, Draytek Vigor130/Asus RT-AC86U Internet
Pixel 4,5&6, iPad 3 Mobile Devices

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Sat Aug 05, 2017 16:43

naigy wrote:
Sat Aug 05, 2017 15:39
...
1. How do I make the plugin start automatically on bootup

You need to change your Plugins() function to return a list, and add a WHERE_SESSIONSTART PluginDescriptor to the list. This sort of thing (from Series2Folder):

Code: Select all

        PluginDescriptor(
            name="AutoSeries2Folder",
            where=PluginDescriptor.WHERE_SESSIONSTART,
            description=_("Auto Series to Folder"),
            needsRestart=False,
            fnc=autoSeries2Folder
        ),
naigy wrote:
Sat Aug 05, 2017 15:39
2. How do I put the Main routine in a loop checking for the file (in the background). Currently when I run the plugin it checks immediately for the file and then seemingly the app closes (I want it to run the Main routine indefinitely. I did try a while loop but it appears to crash the T4. Would like to sort this before I sort point 1 so that if the plugin crashes at least I don't have issues with bootup whilst I get it all functional but if programs on a loop only works for autostart .

You can't just put it into a loop. You need to return control back to the main dispatch loop when the plugin isn't actually doing something. There are undoubtedly several different ways of doing it, but the basic way of doing it is to use a timer to kick it off at regular intervals.

Here's an adapted outline of how Series2Folder does it (initiated from the PluginDescriptor above):

Code: Select all

def autoSeries2Folder(reason, session, **kwargs):
    global _autoSeries2Folder
    global _session

    if _session is None:
        _session = session

    if reason == 0:  # Starting up
        if config.plugins.seriestofolder.auto.value:  # Controls whether background running is allowed
            if not _autoSeries2Folder:
                _autoSeries2Folder = Series2FolderAutoActions(session)  # This object does the work
                _autoSeries2Folder.autoStart()  # Start it running
    elif reason == 1:  # Shutting down
        if _autoSeries2Folder:
            _autoSeries2Folder.autoStop()
            _autoSeries2Folder = None

class Series2FolderAutoActions(Series2FolderActionsBase):

    # Wait for 2 min before starting up, then run every 5 min
    START_DELAY = 2 * 60  # sec Delay time before first run after restart
    RUN_DELAY = 5 * 60  # sec Time between runs

    def __init__(self, session):
        super(Series2FolderAutoActions, self).__init__(session)
        self.runTimer = eTimer()
        self.runTimer.callback.append(self.doRun)  # doRun does the actual work of the plugin

    def autoStart(self):
        self.runTimer.stop()
        self.runTimer.startLongTimer(self.START_DELAY)

    def autoStop(self):
        self.runTimer.stop()
        # Do any wind-up operations

    def doRun(self)
        self.runTimer.startLongTimer(self.RUN_DELAY)
        # Do whatever you do in a run of the plugin

naigy wrote:
Sat Aug 05, 2017 15:39
3. Lastly I want the message to display for a set time period and then disappear

Code: Select all

                        self.session.open(MessageBox,_("Ah, you like the Ihad plugin!\n;-)"), type=MessageBox.TYPE_INFO, timeout=10) # seconds
The user will still be able to dismiss the box before the timeout by using OK or EXIT on the remote.

If you have a look at the SeriesToFolder code, https://bitbucket.org/prl/series2folder, that has some triggers form internal enigma2 events like when recordings stop and when a user stops playing a recording. It also divides up its run into smaller steps so that scanning a lot of files won't hang the UI.

It's probably more complicated than you need, but may be useful to look at. It's also my first attempt at writing a plugin, so there may be better ways of doing it.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Sat Aug 05, 2017 16:53

If you want to persist with the plugin (even if just out of interest) rather than using the OpenWebif interface that MrQuade suggested, the twisted.internet.interfacesIReactorFDSet class allows you to get an event callout whenever a file changes. That's cleaner than polling the file. The twisted module is part of the enigma2 Python environment (and is used in the IceTV plugin, though not that class).
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

naigy
Apprentice
Posts: 61
Joined: Wed May 03, 2017 10:18

Re: Custom Plugin Creation Help

Post by naigy » Sat Aug 05, 2017 17:59

Whoa,

It always amazes me how quickly you get useful responses on this forum. I want to use a custom solution as opposed to the Openwebif API because I can set the position of the window to the corner so it isn't overly obtrusive. If there is a way to do that with openwebif then I would be interested to hear as it would simplify things considerably. I was also looking at a RSS Ticker type solution but I think that is way overkill (at least for the moment).


Will have more of a play later tonight and see what I can sort out.

Again thanks for the prompt suggestions of solutions.

User avatar
MrQuade
Uber Wizard
Posts: 11844
Joined: Sun Jun 24, 2007 13:40
Location: Perth

Re: Custom Plugin Creation Help

Post by MrQuade » Sat Aug 05, 2017 19:25

naigy wrote:
Sat Aug 05, 2017 17:59
If there is a way to do that with openwebif then I would be interested to hear as it would simplify things considerably. I was also looking at a RSS Ticker type solution but I think that is way overkill (at least for the moment). and see what I can sort out.
I don't think there is.

It does make me think though. A generic plugin that changes The location of *all* on screen messages might be a handy thing. Maybe one that allows a user to configure what part of the screen the plugin appears.
Logitech Harmony Ultimate+Elite RCs
Beyonwiz T2/3/U4/V2, DP-S1 PVRs
Denon AVR-X3400h, LG OLED65C7T TV
QNAP TS-410 NAS, Centos File Server (Hosted under KVM)
Ubiquiti UniFi Managed LAN/WLAN, Draytek Vigor130/Asus RT-AC86U Internet
Pixel 4,5&6, iPad 3 Mobile Devices

IanSav
Uber Wizard
Posts: 16846
Joined: Tue May 29, 2007 15:00
Location: Melbourne, Australia

Re: Custom Plugin Creation Help

Post by IanSav » Sat Aug 05, 2017 19:40

Hi MrQuade;
MrQuade wrote:
Sat Aug 05, 2017 19:25
It does make me think though. A generic plugin that changes The location of *all* on screen messages might be a handy thing. Maybe one that allows a user to configure what part of the screen the plugin appears.
All the on screen dialogues are controlled by skin screen definitions. The screens can be positioned as desired. Keep in mind that this will probably cause some unexpected and undesirable results given that many screens are reused in different ways.

Naigy is probably better off using a custom screen so that it doesn't conflict with any other potential uses.

Regards,
Ian.

naigy
Apprentice
Posts: 61
Joined: Wed May 03, 2017 10:18

Re: Custom Plugin Creation Help

Post by naigy » Sat Aug 05, 2017 23:56

Thanks for your help everyone

I have sorted the message time display part of the code (set to 7 seconds). The auto start on bootup I haven't done yet due to the issues with the plugin crashing when I try to utilise loops via timers. I have tried to adapt my code in this regard to be similar to the Series2Folder example supplied however it hasn't worked and generally getting errors about callback or too few or too many arguments. Search for other examples has been unsuccessful also. Have also tried duplicating the loop and sending the loops to each other and fails also (I realise how horrible this is but can't seem to find a way even "with" bad coding practise.

Will keep trying but any further hints of particular examples I can be pointed to would be appreciated.

naigy
Apprentice
Posts: 61
Joined: Wed May 03, 2017 10:18

Re: Custom Plugin Creation Help

Post by naigy » Sun Aug 06, 2017 10:16

Perhaps not an overly elloquent solution but is it possible to run a plugin from a bash script or similar and if so how?. That way I could run my test on file being present using standard python and then run the enigma plugin on each iteration that its needed solely to display the label and than close it after a timeout.

This may even be a better solution as I am wanting to poll the file on a less than 5 second interval ideally (some notifications are redundant 2 to 5 minutes later and I am getting the impression that timers set this short may cause infinte spinning stars or at a minimum make response sluggish. Otherwise is there an interrupt method for enigma but from what I have found online I can't see one.

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Sun Aug 06, 2017 10:41

naigy wrote:
Sat Aug 05, 2017 23:56
... errors about callback or too few or too many arguments. ...

Posting the errors may be helpful to anyone trying to help you.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Sun Aug 06, 2017 11:03

naigy wrote:
Sun Aug 06, 2017 10:16
... timers set this short [~5sec] may cause infinte spinning stars or at a minimum make response sluggish. ...

Short timers, in themselves, don't cause problems like that. There are lots of timers in the code that are set to less than 100ms.

By the way, what timer start function are you using? eTimer.start() takes an argument in ms and is a repeating timer by default. The method eTimer.startLongTimer() has an argument in seconds and is a one-shot.

If you want to run a 5-second single-shot timer, you want to call either myTimer.start(5000, 0), or myTimer.startLongTimer(5). Calling myTimer.start(5) is the same as myTimer.start(5, 1) and will call the timers callbacks repeatedly, every 5ms, until the timer is stopped. The second argument to eTimer.start() is the "repeat" flag and it's 1/true by default.

The spinner is an indication that the timeout on the main dispatch loop has tripped. That means that the code hasn't handed control back to the main loop for more than 2 seconds.

If the problem is happening when a method or function is called from a timer, and the spinner never stops, the code called by the timer is probably in an infinite loop or has hung.

Again, it's hard to say what exactly is happening what there's no code to look at.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Sun Aug 06, 2017 11:29

naigy wrote:
Sun Aug 06, 2017 10:16
Perhaps not an overly elloquent solution but is it possible to run a plugin from a bash script or similar and if so how?. That way I could run my test on file being present using standard python and then run the enigma plugin on each iteration that its needed solely to display the label and than close it after a timeout.

I think you may mean elegant (in good style or taste) rather than eloquent (well-spoken and persuasive, and only one "l") ;)

But what you want to do there is very hard. You can run python from the command line, but a lot of the mechanisms you want to use, like timers, are implemented in the C++ code in enigma2, and called through a SWIG interface. Everything that's imported via "from enigma import" is implemented in the C++ part of enigma2.

I do all my development testing in a running enigma2 system.
naigy wrote:
Sun Aug 06, 2017 10:16
Otherwise is there an interrupt method for enigma but from what I have found online I can't see one.

I'm not sure what you're looking for there. Enigma2 receives Unix signals and catches and processes some of them, but the processing is deferred to the main dispatch loop, so if it's in an infinite loop in code somewhere, the caught signal will never get acted on in the code. E.g. if you send enigma2 a SIGTERM, it will wait until it returns to the dispatch loop, and then shut down in an orderly manner (that's how processes the catch SIGTERM are expected to behave).

If you mean you want to have code in the plugin called back from the main dispatch loop, then you need to put calls back to the code in the plugin into the callbacks of a timer or some other event mechanism (like the recording and playback events that SeriesToFolder gets called from, or an ActionMap to get remote control button presses).

You can use timers like this (untested example code):

Code: Select all

from enigma import eTimer

class myClass:
	STARTDELAY = 10  # seconds
	REPEATTIME = 5  # seconds

	def __init__(self):
		self.myTimer = eTimer()
		self.myTimer.self.myTimer.callback.append(self.timerFunc)
		self.myTimer.startLongTimer(self.STARTDELAY)

	def timerFunc(self):
		self.myTimer.startLongTimer(self.REPEATTIME)
		# do timer stuff...
There are other variants, but that will work for the sort of thing you want to do. Note that to call a method from a timer, you need to supply an object that the method will apply to as well as the method name (self.timerFunction) and the method will always have "self "as its first argument.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

naigy
Apprentice
Posts: 61
Joined: Wed May 03, 2017 10:18

Re: Custom Plugin Creation Help

Post by naigy » Sun Aug 06, 2017 19:29

Thanks Peter,

Appreciate your assistance with this. The error I am getting is the same as one of the ones I saw last night with utilising your example.

The error which is displayed briefly on screen is as follows.
TypeError: __init__ got an unexpected keyword argument 'callback'
I have also attached the crash log file if it is of any help

The code I have just tried is as follows with your sample code incorporated. I have tried making the CheckFunc function part of the MyTimerClass and outside of this class without difference. Have also tried removing the CheckFunc function and just incorporating it as part of the TimerFunc but still get this same issue.

Code: Select all

from Screens.Screen import Screen
from Components.Label import Label
from Components.ActionMap import ActionMap
from Screens.MessageBox import MessageBox
from Plugins.Plugin import PluginDescriptor
from enigma import eTimer
import os

global msgx
global msgTimeout
global waitTimeout
##########################################################


class myTimerClass:
	STARTDELAY = 10  # seconds
	REPEATTIME = 5 	 # seconds

	def __init__(self):
		self.myTimer = eTimer()
		self.myTimer.self.myTimer.callback.append(self.timerFunc)			
		#Note: In regards to the above line I also tried removing the 1st 2 elements (ie. self.myTimer) which appears
		#to be duplicated but got the same error
		self.myTimer.startLongTimer(self.STARTDELAY)

	def timerFunc(self):
		self.myTimer.startLongTimer(self.REPEATTIME)
		self.CheckFunc()

	def CheckFunc(self):
		global msgx
		if os.path.isfile('/tmp/test'):
			msgfile = open('/tmp/test')
			msgx = msgfile.read()
			msgfile.close()
			os.remove('/tmp/test')
			PostMsg()

class PostMsg(Screen):
	global msgx
	skin = """
		<screen position="10,50" size="460,75" title="Home System Update" >
			<widget name="myLabel" position="10,5" size="400,20" font="Regular;20"/>
		</screen>"""

	def __init__(self, session, args = 0, timeout = 7):
		if (msgx == ""):
			self.initTimeout(timeout)
		else:
			self.session = session
			Screen.__init__(self, session)
			self["myLabel"] = Label(_(msgx))
			self["myActionMap"] = ActionMap(["SetupActions"],
			{
				"ok": self.cancel,
				"cancel": self.cancel
			}, -1)
			self.initTimeout(timeout)

	def initTimeout(self, timeout):
		self.timeout = timeout
		if timeout > 0:
			self.timer = eTimer()
			try:
				self.timer.callback.append(self.timerTick)
			except:
				self.timer_conn = self.timer.timeout.connect(self.timerTick)
			self.onExecBegin.append(self.startTimer)
			if self.execing:
				self.timerTick()
			else:
				self.onShown.append(self.__onShown)
			self.timerRunning = True
		else:
			self.timerRunning = False

	def startTimer(self):
		self.timer.start(1000)

	def stopTimer(self):
		if self.timerRunning:
			del self.timer
			self.onExecBegin.remove(self.startTimer)
			self.timerRunning = False

	def timeoutCallback(self):
		self.cancel()

	def timerTick(self):
		if self.execing:
			self.timeout -= 1
			if self.timeout == 0:
				self.timer.stop()
				self.timerRunning = False
				self.timeoutCallback()

	def __onShown(self):
		self.onShown.remove(self.__onShown)

	def cancel(self):
		print "\n[CallMyMsg] cancel\n"
		self.close(None)


##########################################################
def Plugins(**kwargs):
	return PluginDescriptor(
			name="00 Craig Test",
			description="Adapted from IHADTutorial",
			where = PluginDescriptor.WHERE_PLUGINMENU,
			icon="../ihad_tut.png",
			fnc=myTimerClass)
Attachments
Enigma2_crash_2017-08-06_18-54-57.log
(16.88 KiB) Downloaded 109 times
Last edited by naigy on Sun Aug 06, 2017 19:48, edited 1 time in total.

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Sun Aug 06, 2017 19:37

naigy wrote:
Sun Aug 06, 2017 19:29
Thanks Peter,

Appreciate your assistance with this. The error I am getting is the same as one of the ones I saw last night with utilising your example.

The error which is displayed briefly on screen is as follows.
TypeError: __init__ got an unexpected keyword argument 'callback'
I have also attached the crash log file if it is of any help
That's blowing up in main application code. I'll try to work out what the problem is tomorrow.

The code I have just tried is as follows with your sample code incorporated. I have tried making the CheckFunc function part of the MyTimerClass and outside of this class without difference. Have also tried removing the CheckFunc function and just incorporating it as part of the TimerFunc but still get this same issue.
naigy wrote:
Sun Aug 06, 2017 19:29

Code: Select all

...

class myTimerClass:
	...
	def __init__(self):
		...
		self.myTimer.self.myTimer.callback.append(self.timerFunc)  # prl - that's never going to work!
		...
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Sun Aug 06, 2017 23:21

naigy wrote:
Sun Aug 06, 2017 19:29

Code: Select all

def Plugins(**kwargs):
	return PluginDescriptor(
			name="00 Craig Test",
			description="Adapted from IHADTutorial",
			where = PluginDescriptor.WHERE_PLUGINMENU,
			icon="../ihad_tut.png",
			fnc=myTimerClass)  # Also, the fnc argument needs to be the name of a function or bound method, not the name of a class
This one is most likely the cause of the crash.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Mon Aug 07, 2017 13:15

Here's a reworking of your plugin that works. Instead of creating a custom screen, I've derived an AlignableMessageBox from MessageBox and placed it at the top left. You can change the alignment by changing the values of the halign and valign parameters to AlignableMessageBox. I've also added a title parameter and use that to give it your preferred popup box title.

While what IanSav says about Screens generally being sized and positioned by the skin is true, that's not the case for the MessageBox class. I was simply able to over-ride its existing positioning behaviour. Making a MessageBox like that has been something I've wanted to do for a while, to allow for less obtrusive popups for things like changing the subtitles or audio track. What I've done for this exercise is only part of how I'd do the full implementation, but it shows a bit of what's needed.

By using MessageBox, it inherits some useful properties like being able to adjust its size for wide or multi-line messages. Try this:

Code: Select all

(echo \'Twas brillig and the slithy toves; echo Did gyre and gimble in the wabe; echo All mimsy were the borogoves; echo And the mome raths outgrabe) > /tmp/test
Also, inheritance is generally a Good Thing :) There's rather too much inheritance by copy/paste in enigma2.

You've probably also realised that the plugin directory needs a __init__.py (or .pyo) file, even if the source __init__.py file is empty. Otherwise the plugin startup code whinges and doesn't start the plugin.

You'll probably want to consider the wisdom of having the poll interval shorter than the popup timeout (which I've preserved from your code).

Anyway, here it is:

Code: Select all

from Screens.MessageBox import MessageBox
from Plugins.Plugin import PluginDescriptor
from enigma import eTimer, getDesktop, ePoint, RT_HALIGN_LEFT, RT_HALIGN_CENTER, RT_HALIGN_RIGHT, RT_VALIGN_TOP, RT_VALIGN_CENTER, RT_VALIGN_BOTTOM
import os

_postFileMessage = None

class AlignableMessageBox(MessageBox):
	def __init__(self, session, text, type=MessageBox.TYPE_YESNO, timeout=-1, close_on_any_key=False, default=True, enable_input=True, msgBoxID=None, picon=True, simple=False, wizard=False, list=None, skin_name=None, timeout_default=None, title=None, halign=RT_HALIGN_CENTER, valign=RT_VALIGN_CENTER, hoffset=None, voffset=None):
		super(AlignableMessageBox, self).__init__(session, text, type=type, timeout=timeout, close_on_any_key=close_on_any_key, default=default, enable_input=enable_input, msgBoxID=msgBoxID, picon=picon, simple=simple, wizard=wizard, list=list, skin_name=skin_name, timeout_default=timeout_default)
		self.hoffset = hoffset
		self.halign = halign
		if self.hoffset is None:
			if self.halign in (RT_HALIGN_LEFT, RT_HALIGN_LEFT):
				self.hoffset = 20
			else:  # RT_HALIGN_CENTER
				self.hoffset = 0
		self.voffset = voffset
		self.valign = valign
		if self.voffset is None:
			if self.valign == RT_VALIGN_TOP:
				self.voffset = 50
			elif self.valign == RT_VALIGN_BOTTOM:
				self.voffset = -30
			else:  # RT_VALIGN_CENTER
				self.voffset = 0
		if title is not None:
			self.setTitle(title)

	def autoResize(self):
		super(AlignableMessageBox, self).autoResize()
		desktop_w = getDesktop(0).size().width()
		desktop_h = getDesktop(0).size().height()
		w = self.instance.size().width()
		h = self.instance.size().height()
		if self.halign == RT_HALIGN_LEFT:
			x = self.hoffset
		elif self.halign == RT_HALIGN_RIGHT:
			x = desktop_w - w - self.hoffset
		else:  # RT_HALIGN_CENTER
			x = (desktop_w - w) / 2 + self.hoffset
		if self.valign == RT_VALIGN_TOP:
			y = self.voffset
		elif self.valign == RT_VALIGN_BOTTOM:
			y = desktop_h - h - self.voffset
		else:  # RT_VALIGN_CENTER
			y = (desktop_h - h) / 2 + self.voffset
		self.instance.move(ePoint(x, y))

class PostFileMessage:
	STARTDELAY = 10  # seconds
	REPEATTIME = 5  # seconds
	MSGTIMEOUT = 7  # seconds

	def __init__(self, session):
		self.session = session
		self.myTimer = eTimer()
		self.myTimer.callback.append(self.checkFunc)

	def start(self):
		self.myTimer.startLongTimer(self.STARTDELAY)

	def stop(self):
		self.myTimer.stop()

	def checkFunc(self):
		self.myTimer.startLongTimer(self.REPEATTIME)
		if os.path.isfile('/tmp/test'):
			msgfile = open('/tmp/test')
			msgx = msgfile.read().rstrip()
			msgfile.close()
			os.remove('/tmp/test')
			self.session.open(AlignableMessageBox, msgx, title=_("Home System Update"), type=MessageBox.TYPE_INFO, picon=False, timeout=self.MSGTIMEOUT, halign=RT_HALIGN_LEFT, valign=RT_VALIGN_TOP)

def pluginPostFileMessage(reason, session, **kwargs):
	global _postFileMessage

	if reason == 0:
		if not _postFileMessage:
			_postFileMessage = PostFileMessage(session)
			_postFileMessage.start()
	elif reason == 1:
		if _postFileMessage:
			_postFileMessage.stop()
			_postFileMessage = None

def Plugins(**kwargs):
	return PluginDescriptor(
			name="FilePostMessage",
			description="Post a message from a file",
			where = PluginDescriptor.WHERE_SESSIONSTART,
			icon="../ihad_tut.png",
			fnc=pluginPostFileMessage)
E&OE
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

naigy
Apprentice
Posts: 61
Joined: Wed May 03, 2017 10:18

Re: Custom Plugin Creation Help

Post by naigy » Mon Aug 07, 2017 19:22

That looks awesome Peter,

I will try it once some of our recordings are finished. Appears it has been pretty much a complete rewrite except for about 5 lines of my code. Greatly appreciate the time you put into this.

This will really help me as I extend on my home automation setup and integrating the TV as one of the hubs for relaying back important information such as Garage door open, Door bell, Heat lamps left on in bathroom for extended periods etc and possibly even link in to BOM warnings and other external information sources.

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Tue Aug 08, 2017 14:00

No problem. Sometimes the simplest fix is to rewrite most of the code.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Tue Aug 08, 2017 14:05

I thought I posted this last night, but it seems I didn't. :?:
prl wrote:
Mon Aug 07, 2017 13:15
...
You'll probably want to consider the wisdom of having the poll interval shorter than the popup timeout (which I've preserved from your code).
This is one option:

Code: Select all

class PostFileMessage:
	...
		def checkFunc(self):
		if os.path.isfile('/tmp/test'):
			msgfile = open('/tmp/test')
			msgx = msgfile.read().rstrip()
			msgfile.close()
			os.remove('/tmp/test')
			self.session.openWithCallback(lambda ans: self.myTimer.startLongTimer(self.REPEATTIME), AlignableMessageBox, msgx, title=_("Home System Update"), type=MessageBox.TYPE_INFO, picon=False, timeout=self.MSGTIMEOUT, halign=RT_HALIGN_LEFT, valign=RT_VALIGN_TOP)
		else:
			self.myTimer.startLongTimer(self.REPEATTIME)
It only restarts the poll after the MessageBox has closed (the lambda function is the MessageBox's callback).
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

naigy
Apprentice
Posts: 61
Joined: Wed May 03, 2017 10:18

Re: Custom Plugin Creation Help

Post by naigy » Tue Aug 08, 2017 18:12

Thanks again,

Out of interest I was struggling to find many resources online. I came across IhadTutorial but is there any others you would suggest for understanding how to write Enigma plugins and lists of the elements of the various modules etc. I am kind of used to programming in Python (basically anyway) and find using the IDLE useful but don't seem to have a similar thing on the Enigma Platform.

prl
Wizard God
Posts: 32703
Joined: Tue Sep 04, 2007 13:49
Location: Canberra; Black Mountain Tower transmitters

Re: Custom Plugin Creation Help

Post by prl » Tue Aug 08, 2017 18:20

There aren't many explanatory resources online. There's some information in the doc subdirectory of the Beyonwiz easy-ui-4 repository.

Most of what I know comes from reading the code and the skin XML.
Peter
T4 HDMI
U4, T4, T3, T2, V2 test/development machines
Sony BDV-9200W HT system
LG OLED55C9PTA 55" OLED TV

IanSav
Uber Wizard
Posts: 16846
Joined: Tue May 29, 2007 15:00
Location: Melbourne, Australia

Re: Custom Plugin Creation Help

Post by IanSav » Tue Aug 08, 2017 18:29

Hi Naigy,
naigy wrote:
Tue Aug 08, 2017 18:12
Out of interest I was struggling to find many resources online. I came across IhadTutorial but is there any others you would suggest for understanding how to write Enigma plugins and lists of the elements of the various modules etc. I am kind of used to programming in Python (basically anyway) and find using the IDLE useful but don't seem to have a similar thing on the Enigma Platform.
I have been reading the source code, using trial and error or asking for assistance here to get my start in Enigma development. Resources are quite thin on the ground.

I would also suggest caution when reading the code. There is much code rot and poorly written code in the Enigma2 source code. Try to pick up the information you need without duplicating the bad habits of some of the other contributors. For example don't just copy and paste code when you can reuse existing classes.

Good luck. :)

Regards,
Ian.

Post Reply

Return to “Plugins”