diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7506768..d8177ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -41,9 +41,9 @@ Thank you for contributing! This skill helps the entire Indigo development commu ```bash # Fork on GitHub, then: -git clone https://github.com/YOUR-USERNAME/indigo-skill.git -cd indigo-skill -git remote add upstream https://github.com/indigo-community/indigo-skill.git +git clone https://github.com/YOUR-USERNAME/indigo-claude-skill.git +cd indigo-claude-skill +git remote add upstream https://github.com/simons-plugins/indigo-claude-skill.git ``` ### 2. Create a Branch @@ -269,8 +269,8 @@ def example_method(self): ## Questions? -- Open a [Discussion](https://github.com/indigo-community/indigo-skill/discussions) for general questions -- Open an [Issue](https://github.com/indigo-community/indigo-skill/issues) for bugs or feature requests +- Open a [Discussion](https://github.com/simons-plugins/indigo-claude-skill/discussions) for general questions +- Open an [Issue](https://github.com/simons-plugins/indigo-claude-skill/issues) for bugs or feature requests - Tag maintainers with @mention for urgent matters ## Code of Conduct diff --git a/QUICK_START.md b/QUICK_START.md index a8edcaa..fc0530e 100644 --- a/QUICK_START.md +++ b/QUICK_START.md @@ -8,7 +8,7 @@ Get started with the Indigo Plugin Development Skill in 5 minutes! ```bash # Download and run the installer -curl -fsSL https://raw.githubusercontent.com/indigo-community/indigo-skill/main/install.sh | bash +curl -fsSL https://raw.githubusercontent.com/simons-plugins/indigo-claude-skill/main/install.sh | bash ``` ### Option 2: Manual Clone @@ -16,7 +16,7 @@ curl -fsSL https://raw.githubusercontent.com/indigo-community/indigo-skill/main/ ```bash cd /path/to/your/indigo/project mkdir -p .claude/skills -git clone https://github.com/indigo-community/indigo-skill.git .claude/skills/indigo +git clone https://github.com/simons-plugins/indigo-claude-skill.git .claude/skills/indigo ``` ### Option 3: Git Submodule @@ -24,7 +24,7 @@ git clone https://github.com/indigo-community/indigo-skill.git .claude/skills/in ```bash cd /path/to/your/indigo/project mkdir -p .claude/skills -git submodule add https://github.com/indigo-community/indigo-skill.git .claude/skills/indigo +git submodule add https://github.com/simons-plugins/indigo-claude-skill.git .claude/skills/indigo ``` ## Verify Installation @@ -246,7 +246,7 @@ git pull origin main Found the skill helpful? Consider contributing: -1. **Report Issues**: Found incorrect info? [Open an issue](https://github.com/indigo-community/indigo-skill/issues) +1. **Report Issues**: Found incorrect info? [Open an issue](https://github.com/simons-plugins/indigo-claude-skill/issues) 2. **Add Documentation**: See [CONTRIBUTING.md](CONTRIBUTING.md) 3. **Share Examples**: Your plugin could help others! 4. **Improve Docs**: Fix typos, clarify explanations @@ -255,8 +255,8 @@ Found the skill helpful? Consider contributing: - 📚 Read the full [README](README.md) - 📖 Browse [Documentation](docs/README.md) -- 💬 Join [Discussions](https://github.com/indigo-community/indigo-skill/discussions) -- 🐛 Report [Issues](https://github.com/indigo-community/indigo-skill/issues) +- 💬 Join [Discussions](https://github.com/simons-plugins/indigo-claude-skill/discussions) +- 🐛 Report [Issues](https://github.com/simons-plugins/indigo-claude-skill/issues) - 🌐 Visit [Indigo Forum](https://forums.indigodomo.com/viewforum.php?f=18) --- diff --git a/README.md b/README.md index c642cf0..a1c0903 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This is a Claude Code skill that provides expert assistance for developing [Indi cd /path/to/your/indigo/project mkdir -p .claude/skills cd .claude/skills -git clone https://github.com/indigo-community/indigo-skill.git indigo +git clone https://github.com/simons-plugins/indigo-claude-skill.git indigo ``` ### Option 2: Add as submodule @@ -22,14 +22,14 @@ git clone https://github.com/indigo-community/indigo-skill.git indigo ```bash cd /path/to/your/indigo/project mkdir -p .claude/skills -git submodule add https://github.com/indigo-community/indigo-skill.git .claude/skills/indigo +git submodule add https://github.com/simons-plugins/indigo-claude-skill.git .claude/skills/indigo ``` ### Option 3: Symlink (for multiple projects) ```bash # Clone once -git clone https://github.com/indigo-community/indigo-skill.git ~/indigo-skill +git clone https://github.com/simons-plugins/indigo-claude-skill.git ~/indigo-skill # Symlink in each project cd /path/to/your/indigo/project diff --git a/ROADMAP.md b/ROADMAP.md index a1a91c2..f08ef77 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -202,7 +202,7 @@ Help us prioritize by voting on or contributing to these areas: Have an idea not on the roadmap? -1. Open a [Discussion](https://github.com/indigo-community/indigo-skill/discussions) +1. Open a [Discussion](https://github.com/simons-plugins/indigo-claude-skill/discussions) 2. Explain the feature and why it's valuable 3. Gather community feedback 4. Create an issue if there's interest @@ -234,8 +234,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details. ## Questions? -- 💬 Open a [Discussion](https://github.com/indigo-community/indigo-skill/discussions) -- 📋 Review [existing issues](https://github.com/indigo-community/indigo-skill/issues) +- 💬 Open a [Discussion](https://github.com/simons-plugins/indigo-claude-skill/discussions) +- 📋 Review [existing issues](https://github.com/simons-plugins/indigo-claude-skill/issues) - 📧 Contact maintainers --- diff --git a/docs/concepts/plugin-lifecycle.md b/docs/concepts/plugin-lifecycle.md index 8ef41ec..7816d0a 100644 --- a/docs/concepts/plugin-lifecycle.md +++ b/docs/concepts/plugin-lifecycle.md @@ -67,7 +67,7 @@ def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs, **kw **Purpose**: Initialize resources, subscribe to events, start connections **Rules**: -- ✅ Call `super().startup()` first (optional but recommended) +- ❌ Do NOT call `super().startup()` (method doesn't exist in base class) - ✅ Initialize API connections - ✅ Subscribe to Indigo events - ✅ Load persistent data @@ -76,8 +76,7 @@ def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs, **kw ```python def startup(self): - super().startup() - + # Note: Do NOT call super().startup() - it doesn't exist self.logger.info(f"{self.pluginDisplayName} starting") # Now safe to access Indigo database @@ -178,7 +177,7 @@ def runConcurrentThread(self): - ✅ Unsubscribe from events - ✅ Close files and sockets - ✅ Cancel timers -- ✅ Call `super().shutdown()` last (optional but recommended) +- ❌ Do NOT call `super().shutdown()` (method doesn't exist in base class) ```python def shutdown(self): @@ -211,7 +210,7 @@ def shutdown(self): except Exception: pass - super().shutdown() + # Note: Do NOT call super().shutdown() - it doesn't exist ``` **Best Practice**: Wrap cleanup operations in try/except blocks to ensure all cleanup happens even if one step fails. @@ -364,8 +363,7 @@ def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs, **kw self.api_client = None # Will initialize in startup() def startup(self): - super().startup() - + # Note: Do NOT call super().startup() - it doesn't exist api_key = self.pluginPrefs.get("apiKey", "") if api_key: self.api_client = APIClient(api_key) @@ -392,8 +390,7 @@ def shutdown(self): except Exception as exc: self.logger.exception("Error closing API client") - # Always call super - super().shutdown() + # Note: Do NOT call super().shutdown() - it doesn't exist ``` ### Thread-Safe Polling @@ -436,7 +433,7 @@ def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs, **kw self.debug = True # Force debug on during development def startup(self): - super().startup() + # Note: Do NOT call super().startup() - it doesn't exist self.logger.debug("Startup called") self.logger.debug(f"Plugin prefs: {self.pluginPrefs}") ``` @@ -449,7 +446,7 @@ def __init__(self, *args, **kwargs): self.logger.debug("__init__ called") def startup(self): - super().startup() + # Note: Do NOT call super().startup() - it doesn't exist self.logger.debug("startup() called") def runConcurrentThread(self): @@ -463,7 +460,7 @@ def runConcurrentThread(self): def shutdown(self): self.logger.debug("shutdown() called") - super().shutdown() + # Note: Do NOT call super().shutdown() - it doesn't exist ``` ## Common Mistakes @@ -485,28 +482,41 @@ def __init__(self, *args, **kwargs): self.my_device = None def startup(self): - super().startup() + # Note: Do NOT call super().startup() - it doesn't exist try: self.my_device = indigo.devices["MyDevice"] except KeyError: self.logger.error("MyDevice not found") ``` -### ❌ Forgetting to Call `super()` +### ❌ Calling `super()` in Wrong Methods ```python -# WRONG - Always call super() +# WRONG - startup() doesn't have a parent implementation def startup(self): - self.logger.info("Starting") # super().startup() not called! + super().startup() # AttributeError! + self.logger.info("Starting") + +# WRONG - shutdown() doesn't have a parent implementation +def shutdown(self): + super().shutdown() # AttributeError! ``` **Fix**: ```python +# RIGHT - startup() is a pure callback def startup(self): - super().startup() # Always call super first! + # No super() call needed self.logger.info("Starting") + +# RIGHT - shutdown() is a pure callback +def shutdown(self): + # No super() call needed + self.logger.info("Shutting down") ``` +**Remember**: Only call `super()` in `__init__()` (required) and device callbacks like `deviceStartComm()` (recommended) + ### ❌ Using `time.sleep()` in Concurrent Thread ```python @@ -561,18 +571,16 @@ def runConcurrentThread(self): ```python # WRONG - File left open def startup(self): - super().startup() self.log_file = open("/tmp/mylog.txt", "a") def shutdown(self): - super().shutdown() # Forgot to close file! + pass ``` **Fix**: ```python def startup(self): - super().startup() self.log_file = open("/tmp/mylog.txt", "a") def shutdown(self): @@ -581,14 +589,16 @@ def shutdown(self): self.log_file.close() except Exception as exc: self.logger.exception("Error closing log file") - super().shutdown() + # Note: Do NOT call super().shutdown() - it doesn't exist ``` ## Resource Management Checklist - [ ] All instance variables initialized in `__init__()` - [ ] No Indigo database access in `__init__()` -- [ ] `super()` called in all lifecycle methods +- [ ] `super().__init__()` called in `__init__()` (required) +- [ ] `super()` called in device callbacks like `deviceStartComm()` (recommended) +- [ ] `super()` NOT called in `startup()` or `shutdown()` - [ ] Connections opened in `startup()` - [ ] Event subscriptions done in `startup()` - [ ] `self.sleep()` used (not `time.sleep()`) in `runConcurrentThread()` diff --git a/docs/quick-start.md b/docs/quick-start.md index 2870f12..eef7085 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -161,17 +161,25 @@ Before enabling your plugin, verify: ## Common Beginner Mistakes -### ❌ Mistake 1: Forgetting to call `super()` +### ❌ Mistake 1: Calling `super()` on wrong methods ```python -# WRONG - Skips parent initialization +# WRONG - startup() doesn't have a parent implementation def startup(self): + super().startup() # AttributeError! self.logger.info("Starting") -# RIGHT - Always call super first +# RIGHT - Only call super() in __init__ and device callbacks +def __init__(self, pluginId, pluginDisplayName, pluginVersion, pluginPrefs): + super().__init__(pluginId, pluginDisplayName, pluginVersion, pluginPrefs) # REQUIRED! + def startup(self): - super().startup() + # No super() call needed here self.logger.info("Starting") + +def deviceStartComm(self, dev): + super().deviceStartComm(dev) # Good practice for device callbacks + # Your code here ``` ### ❌ Mistake 2: Using `time.sleep()` in concurrent thread @@ -293,7 +301,7 @@ Now that you have a working plugin: - 📖 [Official Plugin Developer's Guide](https://www.indigodomo.com/docs/plugin_guide) - 📚 [Indigo Object Model Reference](https://www.indigodomo.com/docs/object_model_reference) - 💬 [Indigo Developer Forum](https://forums.indigodomo.com/viewforum.php?f=18) -- 🔧 [GitHub: Indigo Skill Repository](https://github.com/indigo-community/indigo-skill) +- 🔧 [GitHub: Indigo Skill Repository](https://github.com/simons-plugins/indigo-claude-skill) --- diff --git a/docs/troubleshooting/README.md b/docs/troubleshooting/README.md index e29998e..6f024c8 100644 --- a/docs/troubleshooting/README.md +++ b/docs/troubleshooting/README.md @@ -49,7 +49,7 @@ plutil -lint Info.plist ```python def startup(self): try: - super().startup() + # Note: Do NOT call super().startup() - it doesn't exist self.logger.debug("Startup: step 1") # ... your code ... self.logger.debug("Startup: step 2") @@ -200,6 +200,6 @@ See [CONTRIBUTING.md](../../CONTRIBUTING.md). If you can't solve your issue: 1. 📋 Check [Indigo Developer Forum](https://forums.indigodomo.com/viewforum.php?f=18) -2. 💬 Ask in [GitHub Discussions](https://github.com/indigo-community/indigo-skill/discussions) +2. 💬 Ask in [GitHub Discussions](https://github.com/simons-plugins/indigo-claude-skill/discussions) 3. 📖 Review [Official Docs](https://www.indigodomo.com/docs/plugin_guide) 4. 📧 Contact Indigo support for platform issues diff --git a/docs/troubleshooting/common-issues.md b/docs/troubleshooting/common-issues.md index 596deda..b484a0d 100644 --- a/docs/troubleshooting/common-issues.md +++ b/docs/troubleshooting/common-issues.md @@ -93,6 +93,45 @@ self.logger.exception(e) # Log it! ``` +4. **AttributeError: 'super' object has no attribute 'startup' (or 'shutdown')** + ``` + Error in plugin execution startup: + File "plugin.py", line 43, in startup + type: 'super' object has no attribute 'startup' + ``` + + **Cause**: Calling `super().startup()` or `super().shutdown()` when these methods don't exist in `indigo.PluginBase` + + **Solution**: Remove the super() calls - these are pure callbacks: + ```python + # WRONG + def startup(self): + super().startup() # Error! + self.logger.info("Starting") + + def shutdown(self): + self.logger.info("Stopping") + super().shutdown() # Error! + + # RIGHT + def startup(self): + # No super() call needed + self.logger.info("Starting") + + def shutdown(self): + # No super() call needed + self.logger.info("Stopping") + ``` + + **Note**: Only these methods need `super()` calls: + - ✅ `__init__()` - **REQUIRED**: `super().__init__(...)` + - ✅ `deviceStartComm()` - Recommended: `super().deviceStartComm(dev)` + - ✅ `deviceStopComm()` - Recommended: `super().deviceStopComm(dev)` + - ✅ `deviceUpdated()` - Recommended: `super().deviceUpdated(origDev, newDev)` + - ✅ `variableUpdated()` - Recommended: `super().variableUpdated(origVar, newVar)` + - ❌ `startup()` - **DO NOT** call super() + - ❌ `shutdown()` - **DO NOT** call super() + ## Device Issues ### Device Won't Create @@ -382,6 +421,90 @@ http://localhost:8176/message/com.example.plugin/api/device.json - Poll less frequently - Use event subscriptions instead of polling when possible +## API Integration Issues + +### 400 Bad Request: Malformed URL + +**Symptoms**: API calls fail with 400 Bad Request, URL has double question marks (`??`) + +**Example Error**: +``` +400 Client Error: Bad Request for url: +http://api.example.com/endpoint?param1=value1?key=abc123 + ↑ Double ? +``` + +**Cause**: Adding `?key=...` to endpoint that already has query parameters + +**Solution**: Check if endpoint already has `?` before adding parameters +```python +# WRONG - Always uses ? +url = f"{base_url}/{endpoint}" +if api_key: + url += f"?key={api_key}" # Breaks if endpoint has ?param=value + +# RIGHT - Check for existing query params +url = f"{base_url}/{endpoint}" +if api_key: + separator = "&" if "?" in endpoint else "?" + url += f"{separator}key={api_key}" +``` + +**Example**: +```python +# Good: handles both cases +def make_api_call(self, endpoint, api_key=None): + url = f"{self.base_url}/{endpoint}" + + if api_key: + # Use & if endpoint already has ?, otherwise use ? + separator = "&" if "?" in endpoint else "?" + url += f"{separator}key={api_key}" + + return requests.get(url) + +# Works with both: +make_api_call("info.json", api_key="abc123") +# → http://api.example.com/info.json?key=abc123 + +make_api_call("schedules.json?start_date=2024-01-01", api_key="abc123") +# → http://api.example.com/schedules.json?start_date=2024-01-01&key=abc123 +``` + +### API Rate Limiting + +**Best Practices**: +- Respect documented rate limits +- Implement exponential backoff on errors +- Cache responses when possible +- Use reasonable polling intervals (5+ minutes for status checks) +- Monitor remaining quota if API provides it + +```python +def _make_api_call(self, endpoint): + try: + response = requests.get(url, timeout=10) + + if response.status_code == 429: + self.logger.warning("Rate limit exceeded") + # Consider backing off or caching more aggressively + return None + + response.raise_for_status() + result = response.json() + + # Log remaining quota if available + if "quota_remaining" in result: + remaining = result["quota_remaining"] + if remaining < 100: + self.logger.warning(f"Low API quota: {remaining} calls remaining") + + return result + except requests.exceptions.Timeout: + self.logger.error("API timeout") + return None +``` + ## Debugging Tips ### Enable Debug Logging diff --git a/reference/README.md b/reference/README.md index edd6aff..4e6bbab 100644 --- a/reference/README.md +++ b/reference/README.md @@ -62,5 +62,5 @@ SDK-CLAUDE.md provides quick references that Claude can use for lookups. ## Questions? - 📚 Check the [main documentation](../docs/) -- 💬 Ask in [Discussions](https://github.com/indigo-community/indigo-skill/discussions) +- 💬 Ask in [Discussions](https://github.com/simons-plugins/indigo-claude-skill/discussions) - 🌐 Visit [Indigo Forum](https://forums.indigodomo.com/viewforum.php?f=18) diff --git a/sdk-examples/README.md b/sdk-examples/README.md index de01a05..3caf76b 100644 --- a/sdk-examples/README.md +++ b/sdk-examples/README.md @@ -279,7 +279,7 @@ For older Indigo versions (Python 2.7), see the reference folder for migration g ## Getting Help - 📚 Check the [SDK Documentation](../docs/sdk/) -- 💬 Ask in [GitHub Discussions](https://github.com/indigo-community/indigo-skill/discussions) +- 💬 Ask in [GitHub Discussions](https://github.com/simons-plugins/indigo-claude-skill/discussions) - 🌐 Visit [Indigo Developer Forum](https://forums.indigodomo.com/viewforum.php?f=18) ## Contributing diff --git a/skill.md b/skill.md index a2e5193..844d6b8 100644 --- a/skill.md +++ b/skill.md @@ -1,6 +1,6 @@ # Indigo Plugin Development Expert -**Repository**: https://github.com/indigo-community/indigo-skill +**Repository**: https://github.com/simons-plugins/indigo-claude-skill **Version**: 2025.1 **Slash command**: `/indigo` @@ -188,6 +188,6 @@ snippets/ This skill is actively maintained by the Indigo community. -- **Report issues**: https://github.com/indigo-community/indigo-skill/issues -- **Contribute**: https://github.com/indigo-community/indigo-skill/pulls -- **Discussions**: https://github.com/indigo-community/indigo-skill/discussions +- **Report issues**: https://github.com/simons-plugins/indigo-claude-skill/issues +- **Contribute**: https://github.com/simons-plugins/indigo-claude-skill/pulls +- **Discussions**: https://github.com/simons-plugins/indigo-claude-skill/discussions diff --git a/snippets/plugin-base-template.py b/snippets/plugin-base-template.py index c43ef15..8782555 100644 --- a/snippets/plugin-base-template.py +++ b/snippets/plugin-base-template.py @@ -62,9 +62,9 @@ def startup(self): - Subscribe to Indigo events - Load persistent data - Validate configuration - """ - super().startup() + Note: startup() is a pure callback - do NOT call super().startup() + """ self.logger.info(f"{self.pluginDisplayName} {self.pluginVersion} starting") # Example: Initialize API client @@ -80,6 +80,8 @@ def shutdown(self): - Close connections - Save persistent data - Clean up resources + + Note: shutdown() is a pure callback - do NOT call super().shutdown() """ self.logger.info(f"{self.pluginDisplayName} shutting down") @@ -87,8 +89,6 @@ def shutdown(self): # if hasattr(self, 'api_client'): # self.api_client.close() - super().shutdown() - def runConcurrentThread(self): """Background thread for periodic tasks.